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 <sosa@chromium.org>
Tested-by: Jay Srinivasan <jaysri@chromium.org>
Commit-Queue: Jay Srinivasan <jaysri@chromium.org>
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());
+}
+
}