Download via HTTP only if enterprise policy allows.
In order to rollout HTTP-downloads for AU to stable channel, we want to
be a bit more conservative to preseve the defense in depth we have now
with HTTPS. So, we're introduced a new enterprise policy which should be
explicitly enabled in order for the payloads to be downloaded via HTTP.
This CL adds the support for honoring such a policy in update engine.
BUG=chromium:235562
TEST=New unit tests added, existing ones updated and they all pass.
TEST=Tested on ZGB with and without policy and it works as expected.
Change-Id: I356efbe237b10031161a57c70cb851c521915a76
Reviewed-on: https://gerrit.chromium.org/gerrit/55805
Reviewed-by: Chris Sosa <[email protected]>
Tested-by: Jay Srinivasan <[email protected]>
Commit-Queue: Jay Srinivasan <[email protected]>
diff --git a/mock_payload_state.h b/mock_payload_state.h
index 65d99da..6513a83 100644
--- a/mock_payload_state.h
+++ b/mock_payload_state.h
@@ -30,7 +30,7 @@
// Getters.
MOCK_METHOD0(GetResponseSignature, std::string());
MOCK_METHOD0(GetPayloadAttemptNumber, uint32_t());
- MOCK_METHOD0(GetUrlIndex, uint32_t());
+ MOCK_METHOD0(GetCurrentUrl, std::string());
MOCK_METHOD0(GetUrlFailureCount, uint32_t());
MOCK_METHOD0(GetUrlSwitchCount, uint32_t());
MOCK_METHOD0(GetBackoffExpiryTime, base::Time());
diff --git a/mock_system_state.h b/mock_system_state.h
index eccfd9b..e03546e 100644
--- a/mock_system_state.h
+++ b/mock_system_state.h
@@ -30,6 +30,7 @@
virtual ~MockSystemState();
MOCK_METHOD0(IsOOBEComplete, bool());
+ MOCK_METHOD0(IsOfficialBuild, bool());
MOCK_METHOD1(set_device_policy, void(const policy::DevicePolicy*));
MOCK_CONST_METHOD0(device_policy, const policy::DevicePolicy*());
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index f2c5c6b..c28e0d6 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -544,7 +544,6 @@
output_object->payload_urls.clear();
for (int i = 0; i < nodeset->nodeNr; i++) {
xmlNode* url_node = nodeset->nodeTab[i];
-
const string codebase(XmlGetProperty(url_node, "codebase"));
if (codebase.empty()) {
LOG(ERROR) << "Omaha Response URL has empty codebase";
@@ -593,10 +592,8 @@
// Append the package name to each URL in our list so that we don't
// propagate the urlBase vs packageName distinctions beyond this point.
// From now on, we only need to use payload_urls.
- for (size_t i = 0; i < output_object->payload_urls.size(); i++) {
+ for (size_t i = 0; i < output_object->payload_urls.size(); i++)
output_object->payload_urls[i] += package_name;
- LOG(INFO) << "Url" << i << ": " << output_object->payload_urls[i];
- }
// Parse the payload size.
off_t size = ParseInt(XmlGetProperty(package_node, "size"));
diff --git a/omaha_response_handler_action.cc b/omaha_response_handler_action.cc
index ad6a087..c85711b 100644
--- a/omaha_response_handler_action.cc
+++ b/omaha_response_handler_action.cc
@@ -39,11 +39,17 @@
}
// All decisions as to which URL should be used have already been done. So,
- // make the download URL as the payload URL at the current url index.
- uint32_t url_index = system_state_->payload_state()->GetUrlIndex();
- LOG(INFO) << "Using Url" << url_index << " as the download url this time";
- CHECK(url_index < response.payload_urls.size());
- install_plan_.download_url = response.payload_urls[url_index];
+ // make the current URL as the download URL.
+ string current_url = system_state_->payload_state()->GetCurrentUrl();
+ if (current_url.empty()) {
+ // This shouldn't happen as we should always supply the HTTPS backup URL.
+ // Handling this anyway, just in case.
+ LOG(ERROR) << "There are no suitable URLs in the response to use.";
+ completer.set_code(kErrorCodeOmahaResponseInvalid);
+ return;
+ }
+
+ install_plan_.download_url = current_url;
// Fill up the other properties based on the response.
install_plan_.payload_size = response.size;
diff --git a/omaha_response_handler_action_unittest.cc b/omaha_response_handler_action_unittest.cc
index 15a1f06..ae8fccb 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -77,6 +77,11 @@
SetString(kPrefsUpdateCheckResponseHash, in.hash))
.WillOnce(Return(true));
}
+
+ string current_url = in.payload_urls.size() ? in.payload_urls[0] : "";
+ EXPECT_CALL(*(mock_system_state->mock_payload_state()), GetCurrentUrl())
+ .WillRepeatedly(Return(current_url));
+
OmahaResponseHandlerAction response_handler_action(mock_system_state);
response_handler_action.set_boot_device(boot_dev);
BondActions(&feeder_action, &response_handler_action);
diff --git a/payload_state.cc b/payload_state.cc
index 5ab6028..3de9e04 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -67,6 +67,12 @@
// Always store the latest response.
response_ = omaha_response;
+ // Compute the candidate URLs first as they are used to calculate the
+ // response signature so that a change in enterprise policy for
+ // HTTP downloads being enabled or not could be honored as soon as the
+ // next update check happens.
+ ComputeCandidateUrls();
+
// Check if the "signature" of this response (i.e. the fields we care about)
// has changed.
string new_response_signature = CalculateResponseSignature();
@@ -85,7 +91,7 @@
// we loaded from the persisted state is a valid value. If the response
// hasn't changed but the URL index is invalid, it's indicative of some
// tampering of the persisted state.
- if (url_index_ >= GetNumUrls()) {
+ if (static_cast<uint32_t>(url_index_) >= candidate_urls_.size()) {
LOG(INFO) << "Resetting all payload state as the url index seems to have "
"been tampered with";
ResetPersistedState();
@@ -152,8 +158,9 @@
LOG(INFO) << "Updating payload state for error code: " << base_error
<< " (" << utils::CodeToString(base_error) << ")";
- if (GetNumUrls() == 0) {
- // This means we got this error even before we got a valid Omaha response.
+ if (candidate_urls_.size() == 0) {
+ // This means we got this error even before we got a valid Omaha response
+ // or don't have any valid candidates in the Omaha response.
// So we should not advance the url_index_ in such cases.
LOG(INFO) << "Ignoring failures until we get a valid Omaha response.";
return;
@@ -307,18 +314,19 @@
void PayloadState::IncrementUrlIndex() {
uint32_t next_url_index = GetUrlIndex() + 1;
- if (next_url_index < GetNumUrls()) {
+ if (next_url_index < candidate_urls_.size()) {
LOG(INFO) << "Incrementing the URL index for next attempt";
SetUrlIndex(next_url_index);
} else {
LOG(INFO) << "Resetting the current URL index (" << GetUrlIndex() << ") to "
- << "0 as we only have " << GetNumUrls() << " URL(s)";
+ << "0 as we only have " << candidate_urls_.size()
+ << " candidate URL(s)";
SetUrlIndex(0);
IncrementPayloadAttemptNumber();
}
// If we have multiple URLs, record that we just switched to another one
- if (GetNumUrls() > 1)
+ if (candidate_urls_.size() > 1)
SetUrlSwitchCount(url_switch_count_ + 1);
// Whenever we update the URL index, we should also clear the URL failure
@@ -377,8 +385,8 @@
void PayloadState::UpdateCurrentDownloadSource() {
current_download_source_ = kNumDownloadSources;
- if (GetUrlIndex() < response_.payload_urls.size()) {
- string current_url = response_.payload_urls[GetUrlIndex()];
+ if (GetUrlIndex() < candidate_urls_.size()) {
+ string current_url = candidate_urls_[GetUrlIndex()];
if (StartsWithASCII(current_url, "https://", false))
current_download_source_ = kDownloadSourceHttpsServer;
else if (StartsWithASCII(current_url, "http://", false))
@@ -552,11 +560,11 @@
string PayloadState::CalculateResponseSignature() {
string response_sign = StringPrintf("NumURLs = %d\n",
- response_.payload_urls.size());
+ candidate_urls_.size());
- for (size_t i = 0; i < response_.payload_urls.size(); i++)
- response_sign += StringPrintf("Url%d = %s\n",
- i, response_.payload_urls[i].c_str());
+ for (size_t i = 0; i < candidate_urls_.size(); i++)
+ response_sign += StringPrintf("Candidate Url%d = %s\n",
+ i, candidate_urls_[i].c_str());
response_sign += StringPrintf("Payload Size = %llu\n"
"Payload Sha256 Hash = %s\n"
@@ -875,4 +883,31 @@
<< GetTotalBytesDownloaded(source);
}
+void PayloadState::ComputeCandidateUrls() {
+ bool http_url_ok = false;
+
+ if (system_state_->IsOfficialBuild()) {
+ const policy::DevicePolicy* policy = system_state_->device_policy();
+ if (!(policy && policy->GetHttpDownloadsEnabled(&http_url_ok) &&
+ http_url_ok))
+ LOG(INFO) << "Downloads via HTTP Url are not enabled by device policy";
+ } else {
+ LOG(INFO) << "Allowing HTTP downloads for unofficial builds";
+ http_url_ok = true;
+ }
+
+ candidate_urls_.clear();
+ for (size_t i = 0; i < response_.payload_urls.size(); i++) {
+ string candidate_url = response_.payload_urls[i];
+ if (StartsWithASCII(candidate_url, "http://", false) && !http_url_ok)
+ continue;
+ candidate_urls_.push_back(candidate_url);
+ LOG(INFO) << "Candidate Url" << (candidate_urls_.size() - 1)
+ << ": " << candidate_url;
+ }
+
+ LOG(INFO) << "Found " << candidate_urls_.size() << " candidate URLs "
+ << "out of " << response_.payload_urls.size() << " URLs supplied";
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_state.h b/payload_state.h
index 1b0899c..e28d5e8 100644
--- a/payload_state.h
+++ b/payload_state.h
@@ -49,8 +49,8 @@
return payload_attempt_number_;
}
- virtual inline uint32_t GetUrlIndex() {
- return url_index_;
+ virtual inline std::string GetCurrentUrl() {
+ return candidate_urls_.size() ? candidate_urls_[url_index_] : "";
}
virtual inline uint32_t GetUrlFailureCount() {
@@ -243,6 +243,14 @@
uint64_t total_bytes_downloaded,
bool log);
+ inline uint32_t GetUrlIndex() {
+ return url_index_;
+ }
+
+ // Computes the list of candidate URLs from the total list of payload URLs in
+ // the Omaha response.
+ void ComputeCandidateUrls();
+
// The global state of the system.
SystemState* system_state_;
@@ -341,18 +349,15 @@
// return value from GetCurrentDownloadSource is used without validation.
uint64_t total_bytes_downloaded_[kNumDownloadSources + 1];
- // Returns the number of URLs in the current response.
- // Note: This value will be 0 if this method is called before we receive
- // the first valid Omaha response in this process.
- uint32_t GetNumUrls() {
- return response_.payload_urls.size();
- }
-
// A small timespan used when comparing wall-clock times for coping
// with the fact that clocks drift and consequently are adjusted
// (either forwards or backwards) via NTP.
static const base::TimeDelta kDurationSlack;
+ // The ordered list of the subset of payload URL candidates which are
+ // allowed as per device policy.
+ std::vector<std::string> candidate_urls_;
+
DISALLOW_COPY_AND_ASSIGN(PayloadState);
};
diff --git a/payload_state_interface.h b/payload_state_interface.h
index 205cb91..cd49abf 100644
--- a/payload_state_interface.h
+++ b/payload_state_interface.h
@@ -69,8 +69,8 @@
// Returns the payload attempt number.
virtual uint32_t GetPayloadAttemptNumber() = 0;
- // Returns the current URL index.
- virtual uint32_t GetUrlIndex() = 0;
+ // Returns the current URL. Returns an empty string if there's no valid URL.
+ virtual std::string GetCurrentUrl() = 0;
// Returns the current URL's failure count.
virtual uint32_t GetUrlFailureCount() = 0;
diff --git a/payload_state_unittest.cc b/payload_state_unittest.cc
index 440d8b7..77a8d02 100644
--- a/payload_state_unittest.cc
+++ b/payload_state_unittest.cc
@@ -42,6 +42,7 @@
"total-bytes-downloaded-from-HttpServer";
static void SetupPayloadStateWith2Urls(string hash,
+ bool http_enabled,
PayloadState* payload_state,
OmahaResponse* response) {
response->payload_urls.clear();
@@ -54,21 +55,29 @@
response->max_failure_count_per_url = 3;
payload_state->SetResponse(*response);
string stored_response_sign = payload_state->GetResponseSignature();
- string expected_response_sign = StringPrintf(
+
+ string expected_url_https_only =
+ "NumURLs = 1\n"
+ "Candidate Url0 = https://test\n";
+
+ string expected_urls_both =
"NumURLs = 2\n"
- "Url0 = http://test\n"
- "Url1 = https://test\n"
- "Payload Size = 523456789\n"
- "Payload Sha256 Hash = %s\n"
- "Metadata Size = 558123\n"
- "Metadata Signature = metasign\n"
- "Is Delta Payload = %d\n"
- "Max Failure Count Per Url = %d\n"
- "Disable Payload Backoff = %d\n",
- hash.c_str(),
- response->is_delta_payload,
- response->max_failure_count_per_url,
- response->disable_payload_backoff);
+ "Candidate Url0 = http://test\n"
+ "Candidate Url1 = https://test\n";
+
+ string expected_response_sign =
+ (http_enabled ? expected_urls_both : expected_url_https_only) +
+ StringPrintf("Payload Size = 523456789\n"
+ "Payload Sha256 Hash = %s\n"
+ "Metadata Size = 558123\n"
+ "Metadata Signature = metasign\n"
+ "Is Delta Payload = %d\n"
+ "Max Failure Count Per Url = %d\n"
+ "Disable Payload Backoff = %d\n",
+ hash.c_str(),
+ response->is_delta_payload,
+ response->max_failure_count_per_url,
+ response->disable_payload_backoff);
EXPECT_EQ(expected_response_sign, stored_response_sign);
}
@@ -118,14 +127,14 @@
"Max Failure Count Per Url = 0\n"
"Disable Payload Backoff = 0\n";
EXPECT_EQ(expected_response_sign, stored_response_sign);
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
}
TEST(PayloadStateTest, SetResponseWorksWithSingleUrl) {
OmahaResponse response;
- response.payload_urls.push_back("http://single.url.test");
+ response.payload_urls.push_back("https://single.url.test");
response.size = 123456789;
response.hash = "hash";
response.metadata_size = 58123;
@@ -156,7 +165,7 @@
payload_state.SetResponse(response);
string stored_response_sign = payload_state.GetResponseSignature();
string expected_response_sign = "NumURLs = 1\n"
- "Url0 = http://single.url.test\n"
+ "Candidate Url0 = https://single.url.test\n"
"Payload Size = 123456789\n"
"Payload Sha256 Hash = hash\n"
"Metadata Size = 58123\n"
@@ -165,7 +174,7 @@
"Max Failure Count Per Url = 0\n"
"Disable Payload Backoff = 0\n";
EXPECT_EQ(expected_response_sign, stored_response_sign);
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("https://single.url.test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
}
@@ -195,13 +204,14 @@
.Times(AtLeast(1));
EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 0))
.Times(AtLeast(1));
+
PayloadState payload_state;
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
payload_state.SetResponse(response);
string stored_response_sign = payload_state.GetResponseSignature();
string expected_response_sign = "NumURLs = 2\n"
- "Url0 = http://multiple.url.test\n"
- "Url1 = https://multiple.url.test\n"
+ "Candidate Url0 = http://multiple.url.test\n"
+ "Candidate Url1 = https://multiple.url.test\n"
"Payload Size = 523456789\n"
"Payload Sha256 Hash = rhash\n"
"Metadata Size = 558123\n"
@@ -210,7 +220,7 @@
"Max Failure Count Per Url = 0\n"
"Disable Payload Backoff = 0\n";
EXPECT_EQ(expected_response_sign, stored_response_sign);
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://multiple.url.test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
}
@@ -245,21 +255,21 @@
// This does a SetResponse which causes all the states to be set to 0 for
// the first time.
- SetupPayloadStateWith2Urls("Hash1235", &payload_state, &response);
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ SetupPayloadStateWith2Urls("Hash1235", true, &payload_state, &response);
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
// Verify that on the first error, the URL index advances to 1.
ErrorCode error = kErrorCodeDownloadMetadataSignatureMismatch;
payload_state.UpdateFailed(error);
- EXPECT_EQ(1, payload_state.GetUrlIndex());
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
// Verify that on the next error, the URL index wraps around to 0.
payload_state.UpdateFailed(error);
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
// Verify that on the next error, it again advances to 1.
payload_state.UpdateFailed(error);
- EXPECT_EQ(1, payload_state.GetUrlIndex());
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
// Verify that we switched URLs three times
EXPECT_EQ(3, payload_state.GetUrlSwitchCount());
@@ -273,19 +283,19 @@
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
// Set the first response.
- SetupPayloadStateWith2Urls("Hash5823", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash5823", true, &payload_state, &response);
// Advance the URL index to 1 by faking an error.
ErrorCode error = kErrorCodeDownloadMetadataSignatureMismatch;
payload_state.UpdateFailed(error);
- EXPECT_EQ(1, payload_state.GetUrlIndex());
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
// Now, slightly change the response and set it again.
- SetupPayloadStateWith2Urls("Hash8225", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash8225", true, &payload_state, &response);
// Make sure the url index was reset to 0 because of the new response.
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
EXPECT_EQ(0,
@@ -343,26 +353,26 @@
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
- SetupPayloadStateWith2Urls("Hash5873", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash5873", true, &payload_state, &response);
// This should advance the URL index.
payload_state.UpdateFailed(kErrorCodeDownloadMetadataSignatureMismatch);
EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetUrlIndex());
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
// This should advance the failure count only.
payload_state.UpdateFailed(kErrorCodeDownloadTransferError);
EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetUrlIndex());
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
EXPECT_EQ(1, payload_state.GetUrlFailureCount());
EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
// This should advance the failure count only.
payload_state.UpdateFailed(kErrorCodeDownloadTransferError);
EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetUrlIndex());
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
EXPECT_EQ(2, payload_state.GetUrlFailureCount());
EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
@@ -372,7 +382,7 @@
// attempt number to be incremented.
payload_state.UpdateFailed(kErrorCodeDownloadTransferError);
EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(2, payload_state.GetUrlSwitchCount());
EXPECT_TRUE(payload_state.ShouldBackoffDownload());
@@ -380,7 +390,7 @@
// This should advance the URL index.
payload_state.UpdateFailed(kErrorCodePayloadHashMismatchError);
EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetUrlIndex());
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(3, payload_state.GetUrlSwitchCount());
EXPECT_TRUE(payload_state.ShouldBackoffDownload());
@@ -389,7 +399,7 @@
// wrap-around of URL index.
payload_state.UpdateFailed(kErrorCodeDownloadMetadataSignatureMissingError);
EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(4, payload_state.GetUrlSwitchCount());
EXPECT_TRUE(payload_state.ShouldBackoffDownload());
@@ -398,7 +408,7 @@
payload_state.UpdateFailed(static_cast<ErrorCode>(
kErrorCodeOmahaRequestHTTPResponseBase + 404));
EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
EXPECT_EQ(1, payload_state.GetUrlFailureCount());
EXPECT_EQ(4, payload_state.GetUrlSwitchCount());
EXPECT_TRUE(payload_state.ShouldBackoffDownload());
@@ -407,17 +417,17 @@
// afterwards.
payload_state.DownloadProgress(progress_bytes);
EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(4, payload_state.GetUrlSwitchCount());
EXPECT_TRUE(payload_state.ShouldBackoffDownload());
// Now, slightly change the response and set it again.
- SetupPayloadStateWith2Urls("Hash8532", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash8532", true, &payload_state, &response);
// Make sure the url index was reset to 0 because of the new response.
EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
EXPECT_FALSE(payload_state.ShouldBackoffDownload());
@@ -445,13 +455,13 @@
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
- SetupPayloadStateWith2Urls("Hash8593", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash8593", true, &payload_state, &response);
// This should just advance the payload attempt number;
EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
payload_state.DownloadComplete();
EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
}
@@ -462,7 +472,7 @@
MockSystemState mock_system_state;
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
- SetupPayloadStateWith2Urls("Hash4427", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash4427", true, &payload_state, &response);
// Generate enough events to advance URL index, failure count and
// payload attempt number all to 1.
@@ -470,7 +480,7 @@
payload_state.UpdateFailed(kErrorCodeDownloadMetadataSignatureMismatch);
payload_state.UpdateFailed(kErrorCodeDownloadTransferError);
EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetUrlIndex());
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
EXPECT_EQ(1, payload_state.GetUrlFailureCount());
EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
@@ -495,12 +505,12 @@
// response was different. We want to specifically test that even if the
// response is same, we should reset the state if we find it corrupted.
EXPECT_TRUE(payload_state.Initialize(&mock_system_state2));
- SetupPayloadStateWith2Urls("Hash4427", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash4427", true, &payload_state, &response);
// Make sure all counters get reset to 0 because of the corrupted URL index
// we supplied above.
EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetUrlFailureCount());
EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
}
@@ -512,7 +522,7 @@
MockSystemState mock_system_state;
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
- SetupPayloadStateWith2Urls("Hash6437", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash6437", true, &payload_state, &response);
// Simulate a successful download and see that we're ready to download
// again without any backoff as this is a delta payload.
@@ -525,7 +535,7 @@
// a delta payload.
payload_state.UpdateFailed(kErrorCodeDownloadMetadataSignatureMismatch);
payload_state.UpdateFailed(kErrorCodeDownloadMetadataSignatureMismatch);
- EXPECT_EQ(0, payload_state.GetUrlIndex());
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
EXPECT_FALSE(payload_state.ShouldBackoffDownload());
}
@@ -554,7 +564,7 @@
MockSystemState mock_system_state;
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
- SetupPayloadStateWith2Urls("Hash8939", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash8939", true, &payload_state, &response);
CheckPayloadBackoffState(&payload_state, 1, TimeDelta::FromDays(1));
CheckPayloadBackoffState(&payload_state, 2, TimeDelta::FromDays(2));
@@ -575,7 +585,7 @@
MockSystemState mock_system_state;
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
- SetupPayloadStateWith2Urls("Hash8939", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash8939", true, &payload_state, &response);
// Simulate a successful download and see that we are ready to download
// again without any backoff.
@@ -601,7 +611,7 @@
int http_total = 0;
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
- SetupPayloadStateWith2Urls("Hash3286", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash3286", true, &payload_state, &response);
// Simulate a previous attempt with in order to set an initial non-zero value
// for the total bytes downloaded for HTTP.
@@ -617,13 +627,13 @@
// Change the response hash so as to simulate a new response which will
// reset the current bytes downloaded, but not the total bytes downloaded.
- SetupPayloadStateWith2Urls("Hash9904", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash9904", true, &payload_state, &response);
// First, simulate successful download of a few bytes over HTTP.
int first_chunk = 5000000;
http_total += first_chunk;
payload_state.DownloadProgress(first_chunk);
- // Test that first all progress is made on HTTP and none on HTTPs.
+ // Test that first all progress is made on HTTP and none on HTTPS.
EXPECT_EQ(first_chunk,
payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
EXPECT_EQ(http_total,
@@ -637,7 +647,7 @@
ErrorCode error = kErrorCodeDownloadMetadataSignatureMismatch;
payload_state.UpdateFailed(error);
- // Test that no new progress is made on HTTP and new progress is on HTTPs.
+ // Test that no new progress is made on HTTP and new progress is on HTTPS.
int second_chunk = 23456789;
https_total += second_chunk;
payload_state.DownloadProgress(second_chunk);
@@ -717,7 +727,7 @@
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
// Set the first response.
- SetupPayloadStateWith2Urls("Hash5823", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash5823", true, &payload_state, &response);
int num_bytes = 10000;
payload_state.DownloadProgress(num_bytes);
@@ -791,7 +801,7 @@
// Check that durations are correct for a successful update where
// time has advanced 7 seconds on the wall clock and 4 seconds on
// the monotonic clock.
- SetupPayloadStateWith2Urls("Hash8593", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash8593", true, &payload_state, &response);
fake_clock.SetWallclockTime(Time::FromInternalValue(8000000));
fake_clock.SetMonotonicTime(Time::FromInternalValue(6000000));
payload_state.UpdateSucceeded();
@@ -799,7 +809,7 @@
EXPECT_EQ(payload_state.GetUpdateDurationUptime().InMicroseconds(), 4000000);
// Check that durations are reset when a new response comes in.
- SetupPayloadStateWith2Urls("Hash8594", &payload_state, &response);
+ SetupPayloadStateWith2Urls("Hash8594", true, &payload_state, &response);
EXPECT_EQ(payload_state.GetUpdateDuration().InMicroseconds(), 0);
EXPECT_EQ(payload_state.GetUpdateDurationUptime().InMicroseconds(), 0);
@@ -831,4 +841,68 @@
EXPECT_TRUE(utils::RecursiveUnlinkDir(temp_dir));
}
+TEST(PayloadStateTest, CandidateUrlsComputedCorrectly) {
+ OmahaResponse response;
+ MockSystemState mock_system_state;
+ PayloadState payload_state;
+
+ // Pretend that this is an offical build so that the HTTP download policy
+ // is honored.
+ EXPECT_CALL(mock_system_state, IsOfficialBuild())
+ .WillRepeatedly(Return(true));
+
+ policy::MockDevicePolicy disable_http_policy;
+ EXPECT_CALL(mock_system_state, device_policy())
+ .WillRepeatedly(Return(&disable_http_policy));
+ EXPECT_CALL(disable_http_policy, GetHttpDownloadsEnabled(_))
+ .WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(true)));
+
+ EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
+
+ // Set the first response.
+ SetupPayloadStateWith2Urls("Hash8433", false, &payload_state, &response);
+
+ // Check that we skip the HTTP URL and use only the HTTPS url.
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
+
+ // Advance the URL index to 1 by faking an error.
+ ErrorCode error = kErrorCodeDownloadMetadataSignatureMismatch;
+ payload_state.UpdateFailed(error);
+
+ // Check that we still skip the HTTP URL and use only the HTTPS url.
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
+ EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
+
+ // Now, slightly change the response and set it again.
+ SetupPayloadStateWith2Urls("Hash2399", false, &payload_state, &response);
+
+ // Check that we still skip the HTTP URL and use only the HTTPS url.
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
+
+ // Now, pretend that the HTTP policy is turned on. We want to make sure
+ // the new policy is honored.
+ policy::MockDevicePolicy enable_http_policy;
+ EXPECT_CALL(mock_system_state, device_policy())
+ .WillRepeatedly(Return(&enable_http_policy));
+ EXPECT_CALL(enable_http_policy, GetHttpDownloadsEnabled(_))
+ .WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true)));
+
+ // Now, set the same response using the same hash
+ // so that we can test that the state is reset not because of the
+ // hash but because of the policy change which results in candidate url
+ // list change.
+ SetupPayloadStateWith2Urls("Hash2399", true, &payload_state, &response);
+
+ // Check that we use the HTTP URL now and the failure count is reset.
+ EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
+ EXPECT_EQ(0, payload_state.GetUrlFailureCount());
+
+ // Fake a failure and see if we're moving over to the HTTPS url and update
+ // the URL switch count properly.
+ payload_state.UpdateFailed(error);
+ EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
+ EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
+ EXPECT_EQ(0, payload_state.GetUrlFailureCount());
+}
+
}
diff --git a/real_system_state.h b/real_system_state.h
index 42d1509..83f3ac1 100644
--- a/real_system_state.h
+++ b/real_system_state.h
@@ -25,6 +25,7 @@
virtual ~RealSystemState() {}
virtual bool IsOOBEComplete();
+ virtual bool IsOfficialBuild();
virtual inline void set_device_policy(
const policy::DevicePolicy* device_policy) {
diff --git a/system_state.cc b/system_state.cc
index da18500..2f7d0dd 100644
--- a/system_state.cc
+++ b/system_state.cc
@@ -64,4 +64,8 @@
return file_util::PathExists(FilePath(kOOBECompletedMarker));
}
+bool RealSystemState::IsOfficialBuild() {
+ return utils::IsOfficialBuild();
+}
+
} // namespace chromeos_update_engine
diff --git a/system_state.h b/system_state.h
index 313d670..4f3c98f 100644
--- a/system_state.h
+++ b/system_state.h
@@ -40,6 +40,10 @@
// False otherwise.
virtual bool IsOOBEComplete() = 0;
+ // Returns true if we're running an official (i.e, non-dev, non-test) build.
+ // False otherwise.
+ virtual bool IsOfficialBuild() = 0;
+
// Sets or gets the latest device policy.
virtual void set_device_policy(const policy::DevicePolicy* device_policy) = 0;
virtual const policy::DevicePolicy* device_policy() const = 0;
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index ff3236c..095de23 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -237,11 +237,14 @@
EXPECT_CALL(*mock_system_state_.mock_payload_state(), UpdateFailed(_))
.Times(0);
OmahaResponse response;
- response.payload_urls.push_back("http://url");
+ string url1 = "http://url1";
+ response.payload_urls.push_back(url1);
response.payload_urls.push_back("https://url");
+ EXPECT_CALL(*(mock_system_state_.mock_payload_state()), GetCurrentUrl())
+ .WillRepeatedly(Return(url1));
mock_system_state_.mock_payload_state()->SetResponse(response);
attempter_.ScheduleErrorEventAction();
- EXPECT_EQ(0, mock_system_state_.mock_payload_state()->GetUrlIndex());
+ EXPECT_EQ(url1, mock_system_state_.mock_payload_state()->GetCurrentUrl());
}
TEST_F(UpdateAttempterTest, ScheduleErrorEventActionTest) {