Remove libcurl support from update_engine_sideload.
While sideloading an update from recovery we don't need nor want to
download payload from HTTP(S) URLs, only local file:// are supported.
This patch moves libcurl_http_fetcher and certificate_checker files out
of libpayload_consumer dropping the libcurl and libssl dependencies from
it and the update_engine_sideload.
Bug: 27178350
TEST=build UE for Brillo and Android. Unittests still pass and
update_engine_sideload doesn't link to libcurl.
Change-Id: Iffefdb094654f7277dc825c041fe55aac9ee8756
diff --git a/common/certificate_checker.cc b/common/certificate_checker.cc
deleted file mode 100644
index 86df950..0000000
--- a/common/certificate_checker.cc
+++ /dev/null
@@ -1,204 +0,0 @@
-//
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include "update_engine/common/certificate_checker.h"
-
-#include <string>
-
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <curl/curl.h>
-#include <openssl/evp.h>
-#include <openssl/ssl.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/prefs_interface.h"
-#include "update_engine/common/utils.h"
-
-using std::string;
-
-namespace chromeos_update_engine {
-
-bool OpenSSLWrapper::GetCertificateDigest(X509_STORE_CTX* x509_ctx,
- int* out_depth,
- unsigned int* out_digest_length,
- uint8_t* out_digest) const {
- TEST_AND_RETURN_FALSE(out_digest);
- X509* certificate = X509_STORE_CTX_get_current_cert(x509_ctx);
- TEST_AND_RETURN_FALSE(certificate);
- int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
- if (out_depth)
- *out_depth = depth;
-
- unsigned int len;
- const EVP_MD* digest_function = EVP_sha256();
- bool success = X509_digest(certificate, digest_function, out_digest, &len);
-
- if (success && out_digest_length)
- *out_digest_length = len;
- return success;
-}
-
-// static
-CertificateChecker* CertificateChecker::cert_checker_singleton_ = nullptr;
-
-CertificateChecker::CertificateChecker(PrefsInterface* prefs,
- OpenSSLWrapper* openssl_wrapper)
- : prefs_(prefs), openssl_wrapper_(openssl_wrapper) {
-}
-
-CertificateChecker::~CertificateChecker() {
- if (cert_checker_singleton_ == this)
- cert_checker_singleton_ = nullptr;
-}
-
-void CertificateChecker::Init() {
- CHECK(cert_checker_singleton_ == nullptr);
- cert_checker_singleton_ = this;
-}
-
-// static
-CURLcode CertificateChecker::ProcessSSLContext(CURL* curl_handle,
- SSL_CTX* ssl_ctx,
- void* ptr) {
- ServerToCheck* server_to_check = reinterpret_cast<ServerToCheck*>(ptr);
-
- if (!cert_checker_singleton_) {
- DLOG(WARNING) << "No CertificateChecker singleton initialized.";
- return CURLE_FAILED_INIT;
- }
-
- // From here we set the SSL_CTX to another callback, from the openssl library,
- // which will be called after each server certificate is validated. However,
- // since openssl does not allow us to pass our own data pointer to the
- // callback, the certificate check will have to be done statically. Since we
- // need to know which update server we are using in order to check the
- // certificate, we hardcode Chrome OS's two known update servers here, and
- // define a different static callback for each. Since this code should only
- // run in official builds, this should not be a problem. However, if an update
- // server different from the ones listed here is used, the check will not
- // take place.
- int (*verify_callback)(int, X509_STORE_CTX*);
- switch (*server_to_check) {
- case ServerToCheck::kDownload:
- verify_callback = &CertificateChecker::VerifySSLCallbackDownload;
- break;
- case ServerToCheck::kUpdate:
- verify_callback = &CertificateChecker::VerifySSLCallbackUpdate;
- break;
- case ServerToCheck::kNone:
- verify_callback = nullptr;
- break;
- }
-
- SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_callback);
- return CURLE_OK;
-}
-
-// static
-int CertificateChecker::VerifySSLCallbackDownload(int preverify_ok,
- X509_STORE_CTX* x509_ctx) {
- return VerifySSLCallback(preverify_ok, x509_ctx, ServerToCheck::kDownload);
-}
-
-// static
-int CertificateChecker::VerifySSLCallbackUpdate(int preverify_ok,
- X509_STORE_CTX* x509_ctx) {
- return VerifySSLCallback(preverify_ok, x509_ctx, ServerToCheck::kUpdate);
-}
-
-// static
-int CertificateChecker::VerifySSLCallback(int preverify_ok,
- X509_STORE_CTX* x509_ctx,
- ServerToCheck server_to_check) {
- CHECK(cert_checker_singleton_ != nullptr);
- return cert_checker_singleton_->CheckCertificateChange(
- preverify_ok, x509_ctx, server_to_check) ? 1 : 0;
-}
-
-bool CertificateChecker::CheckCertificateChange(int preverify_ok,
- X509_STORE_CTX* x509_ctx,
- ServerToCheck server_to_check) {
- TEST_AND_RETURN_FALSE(prefs_ != nullptr);
-
- // If pre-verification failed, we are not interested in the current
- // certificate. We store a report to UMA and just propagate the fail result.
- if (!preverify_ok) {
- NotifyCertificateChecked(server_to_check, CertificateCheckResult::kFailed);
- return false;
- }
-
- int depth;
- unsigned int digest_length;
- uint8_t digest[EVP_MAX_MD_SIZE];
-
- if (!openssl_wrapper_->GetCertificateDigest(x509_ctx,
- &depth,
- &digest_length,
- digest)) {
- LOG(WARNING) << "Failed to generate digest of X509 certificate "
- << "from update server.";
- NotifyCertificateChecked(server_to_check, CertificateCheckResult::kValid);
- return true;
- }
-
- // We convert the raw bytes of the digest to an hex string, for storage in
- // prefs.
- string digest_string = base::HexEncode(digest, digest_length);
-
- string storage_key =
- base::StringPrintf("%s-%d-%d", kPrefsUpdateServerCertificate,
- static_cast<int>(server_to_check), depth);
- string stored_digest;
- // If there's no stored certificate, we just store the current one and return.
- if (!prefs_->GetString(storage_key, &stored_digest)) {
- if (!prefs_->SetString(storage_key, digest_string)) {
- LOG(WARNING) << "Failed to store server certificate on storage key "
- << storage_key;
- }
- NotifyCertificateChecked(server_to_check, CertificateCheckResult::kValid);
- return true;
- }
-
- // Certificate changed, we store a report to UMA and store the most recent
- // certificate.
- if (stored_digest != digest_string) {
- if (!prefs_->SetString(storage_key, digest_string)) {
- LOG(WARNING) << "Failed to store server certificate on storage key "
- << storage_key;
- }
- LOG(INFO) << "Certificate changed from " << stored_digest << " to "
- << digest_string << ".";
- NotifyCertificateChecked(server_to_check,
- CertificateCheckResult::kValidChanged);
- return true;
- }
-
- NotifyCertificateChecked(server_to_check, CertificateCheckResult::kValid);
- // Since we don't perform actual SSL verification, we return success.
- return true;
-}
-
-void CertificateChecker::NotifyCertificateChecked(
- ServerToCheck server_to_check,
- CertificateCheckResult result) {
- if (observer_)
- observer_->CertificateChecked(server_to_check, result);
-}
-
-} // namespace chromeos_update_engine
diff --git a/common/certificate_checker.h b/common/certificate_checker.h
deleted file mode 100644
index c785192..0000000
--- a/common/certificate_checker.h
+++ /dev/null
@@ -1,175 +0,0 @@
-//
-// Copyright (C) 2011 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#ifndef UPDATE_ENGINE_COMMON_CERTIFICATE_CHECKER_H_
-#define UPDATE_ENGINE_COMMON_CERTIFICATE_CHECKER_H_
-
-#include <curl/curl.h>
-#include <openssl/ssl.h>
-
-#include <string>
-
-#include <base/macros.h>
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-
-namespace chromeos_update_engine {
-
-class PrefsInterface;
-
-// Wrapper for openssl operations with the certificates.
-class OpenSSLWrapper {
- public:
- OpenSSLWrapper() = default;
- virtual ~OpenSSLWrapper() = default;
-
- // Takes an openssl X509_STORE_CTX, extracts the corresponding certificate
- // from it and calculates its fingerprint (SHA256 digest). Returns true on
- // success and false otherwise.
- //
- // |x509_ctx| is the pointer to the openssl object that holds the certificate.
- // |out_depth| is the depth of the current certificate, in the certificate
- // chain.
- // |out_digest_length| is the length of the generated digest.
- // |out_digest| is the byte array where the digest itself will be written.
- // It should be big enough to hold a SHA1 digest (e.g. EVP_MAX_MD_SIZE).
- virtual bool GetCertificateDigest(X509_STORE_CTX* x509_ctx,
- int* out_depth,
- unsigned int* out_digest_length,
- uint8_t* out_digest) const;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(OpenSSLWrapper);
-};
-
-// The values in this enum are replicated in the metrics server. See metrics.h
-// for instructions on how to update these values in the server side.
-enum class CertificateCheckResult {
- // The certificate is valid and the same as seen before or the first time we
- // see a certificate.
- kValid,
- // The certificate is valid, but is different than a previously seen
- // certificate for the selected server.
- kValidChanged,
- // The certificate validation failed.
- kFailed,
-
- // This value must be the last entry.
- kNumConstants
-};
-
-// These values are used to generate the keys of files persisted via prefs.
-// This means that changing these will cause loss of information on metrics
-// reporting, during the transition. These values are also mapped to a metric
-// name in metrics.cc, so adding values here requires to assign a new metric
-// name in that file.
-enum class ServerToCheck {
- kUpdate = 0,
- kDownload,
-
- // Ignore this server.
- kNone,
-};
-
-// Responsible for checking whether update server certificates change, and
-// reporting to UMA when this happens. Since all state information is persisted,
-// and openssl forces us to use a static callback with no data pointer, this
-// class is entirely static.
-class CertificateChecker {
- public:
- class Observer {
- public:
- virtual ~Observer() = default;
-
- // Called whenever a certificate is checked for the server |server_to_check|
- // passing the result of said certificate check.
- virtual void CertificateChecked(ServerToCheck server_to_check,
- CertificateCheckResult result) = 0;
- };
-
- CertificateChecker(PrefsInterface* prefs, OpenSSLWrapper* openssl_wrapper);
- ~CertificateChecker();
-
- // This callback is called by libcurl just before the initialization of an
- // SSL connection after having processed all other SSL related options. Used
- // to check if server certificates change. |cert_checker| is expected to be a
- // pointer to the CertificateChecker instance.
- static CURLcode ProcessSSLContext(CURL* curl_handle,
- SSL_CTX* ssl_ctx,
- void* cert_checker);
-
- // Initialize this class as the singleton instance. Only one instance can be
- // initialized at a time and it should be initialized before other methods
- // can be used.
- void Init();
-
- // Set the certificate observer to the passed instance. To remove the
- // observer, pass a nullptr. The |observer| instance must be valid while this
- // CertificateChecker verifies certificates.
- void SetObserver(Observer* observer) { observer_ = observer; }
-
- private:
- FRIEND_TEST(CertificateCheckerTest, NewCertificate);
- FRIEND_TEST(CertificateCheckerTest, SameCertificate);
- FRIEND_TEST(CertificateCheckerTest, ChangedCertificate);
- FRIEND_TEST(CertificateCheckerTest, FailedCertificate);
-
- // These callbacks are asynchronously called by openssl after initial SSL
- // verification. They are used to perform any additional security verification
- // on the connection, but we use them here to get hold of the server
- // certificate, in order to determine if it has changed since the last
- // connection. Since openssl forces us to do this statically, we define two
- // different callbacks for the two different official update servers, and only
- // assign the correspondent one. The assigned callback is then called once per
- // each certificate on the server and returns 1 for success and 0 for failure.
- static int VerifySSLCallbackDownload(int preverify_ok,
- X509_STORE_CTX* x509_ctx);
- static int VerifySSLCallbackUpdate(int preverify_ok,
- X509_STORE_CTX* x509_ctx);
- static int VerifySSLCallback(int preverify_ok,
- X509_STORE_CTX* x509_ctx,
- ServerToCheck server_to_check);
-
- // Checks if server certificate stored in |x509_ctx| has changed since last
- // connection to that same server, specified by |server_to_check|.
- // This is called by the callbacks defined above. The result of the
- // certificate check is passed to the observer, if any. Returns true on
- // success and false otherwise.
- bool CheckCertificateChange(int preverify_ok,
- X509_STORE_CTX* x509_ctx,
- ServerToCheck server_to_check);
-
- // Notifies the observer, if any, of a certificate checking.
- void NotifyCertificateChecked(ServerToCheck server_to_check,
- CertificateCheckResult result);
-
- // The CertificateChecker singleton instance.
- static CertificateChecker* cert_checker_singleton_;
-
- // Prefs instance used to store the certificates seen in the past.
- PrefsInterface* prefs_;
-
- // The wrapper for openssl operations.
- OpenSSLWrapper* openssl_wrapper_;
-
- // The observer called whenever a certificate is checked, if not null.
- Observer* observer_{nullptr};
-
- DISALLOW_COPY_AND_ASSIGN(CertificateChecker);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_COMMON_CERTIFICATE_CHECKER_H_
diff --git a/common/certificate_checker_unittest.cc b/common/certificate_checker_unittest.cc
deleted file mode 100644
index c30acc5..0000000
--- a/common/certificate_checker_unittest.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-//
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include "update_engine/common/certificate_checker.h"
-
-#include <string>
-
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/mock_certificate_checker.h"
-#include "update_engine/common/mock_prefs.h"
-
-using ::testing::DoAll;
-using ::testing::Return;
-using ::testing::SetArgumentPointee;
-using ::testing::SetArrayArgument;
-using ::testing::_;
-using std::string;
-
-namespace chromeos_update_engine {
-
-class MockCertificateCheckObserver : public CertificateChecker::Observer {
- public:
- MOCK_METHOD2(CertificateChecked,
- void(ServerToCheck server_to_check,
- CertificateCheckResult result));
-};
-
-class CertificateCheckerTest : public testing::Test {
- protected:
- void SetUp() override {
- cert_key_ = base::StringPrintf("%s-%d-%d",
- cert_key_prefix_.c_str(),
- static_cast<int>(server_to_check_),
- depth_);
- cert_checker.Init();
- cert_checker.SetObserver(&observer_);
- }
-
- void TearDown() override {
- cert_checker.SetObserver(nullptr);
- }
-
- MockPrefs prefs_;
- MockOpenSSLWrapper openssl_wrapper_;
- // Parameters of our mock certificate digest.
- int depth_{0};
- unsigned int length_{4};
- uint8_t digest_[4]{0x17, 0x7D, 0x07, 0x5F};
- string digest_hex_{"177D075F"};
- string diff_digest_hex_{"1234ABCD"};
- string cert_key_prefix_{kPrefsUpdateServerCertificate};
- ServerToCheck server_to_check_{ServerToCheck::kUpdate};
- string cert_key_;
-
- testing::StrictMock<MockCertificateCheckObserver> observer_;
- CertificateChecker cert_checker{&prefs_, &openssl_wrapper_};
-};
-
-// check certificate change, new
-TEST_F(CertificateCheckerTest, NewCertificate) {
- EXPECT_CALL(openssl_wrapper_, GetCertificateDigest(nullptr, _, _, _))
- .WillOnce(DoAll(
- SetArgumentPointee<1>(depth_),
- SetArgumentPointee<2>(length_),
- SetArrayArgument<3>(digest_, digest_ + 4),
- Return(true)));
- EXPECT_CALL(prefs_, GetString(cert_key_, _)).WillOnce(Return(false));
- EXPECT_CALL(prefs_, SetString(cert_key_, digest_hex_)).WillOnce(Return(true));
- EXPECT_CALL(observer_,
- CertificateChecked(server_to_check_,
- CertificateCheckResult::kValid));
- ASSERT_TRUE(
- cert_checker.CheckCertificateChange(1, nullptr, server_to_check_));
-}
-
-// check certificate change, unchanged
-TEST_F(CertificateCheckerTest, SameCertificate) {
- EXPECT_CALL(openssl_wrapper_, GetCertificateDigest(nullptr, _, _, _))
- .WillOnce(DoAll(
- SetArgumentPointee<1>(depth_),
- SetArgumentPointee<2>(length_),
- SetArrayArgument<3>(digest_, digest_ + 4),
- Return(true)));
- EXPECT_CALL(prefs_, GetString(cert_key_, _))
- .WillOnce(DoAll(SetArgumentPointee<1>(digest_hex_), Return(true)));
- EXPECT_CALL(prefs_, SetString(_, _)).Times(0);
- EXPECT_CALL(observer_,
- CertificateChecked(server_to_check_,
- CertificateCheckResult::kValid));
- ASSERT_TRUE(
- cert_checker.CheckCertificateChange(1, nullptr, server_to_check_));
-}
-
-// check certificate change, changed
-TEST_F(CertificateCheckerTest, ChangedCertificate) {
- EXPECT_CALL(openssl_wrapper_, GetCertificateDigest(nullptr, _, _, _))
- .WillOnce(DoAll(
- SetArgumentPointee<1>(depth_),
- SetArgumentPointee<2>(length_),
- SetArrayArgument<3>(digest_, digest_ + 4),
- Return(true)));
- EXPECT_CALL(prefs_, GetString(cert_key_, _))
- .WillOnce(DoAll(SetArgumentPointee<1>(diff_digest_hex_), Return(true)));
- EXPECT_CALL(observer_,
- CertificateChecked(server_to_check_,
- CertificateCheckResult::kValidChanged));
- EXPECT_CALL(prefs_, SetString(cert_key_, digest_hex_)).WillOnce(Return(true));
- ASSERT_TRUE(
- cert_checker.CheckCertificateChange(1, nullptr, server_to_check_));
-}
-
-// check certificate change, failed
-TEST_F(CertificateCheckerTest, FailedCertificate) {
- EXPECT_CALL(observer_, CertificateChecked(server_to_check_,
- CertificateCheckResult::kFailed));
- EXPECT_CALL(prefs_, GetString(_, _)).Times(0);
- EXPECT_CALL(openssl_wrapper_, GetCertificateDigest(_, _, _, _)).Times(0);
- ASSERT_FALSE(
- cert_checker.CheckCertificateChange(0, nullptr, server_to_check_));
-}
-
-} // namespace chromeos_update_engine
diff --git a/common/file_fetcher.cc b/common/file_fetcher.cc
index 77dadd1..d0a109b 100644
--- a/common/file_fetcher.cc
+++ b/common/file_fetcher.cc
@@ -27,7 +27,6 @@
#include <base/strings/stringprintf.h>
#include <brillo/streams/file_stream.h>
-#include "update_engine/common/certificate_checker.h"
#include "update_engine/common/hardware_interface.h"
#include "update_engine/common/platform_constants.h"
diff --git a/common/hash_calculator_unittest.cc b/common/hash_calculator_unittest.cc
index 27dbc56..436e6a7 100644
--- a/common/hash_calculator_unittest.cc
+++ b/common/hash_calculator_unittest.cc
@@ -25,7 +25,6 @@
#include <brillo/secure_blob.h>
#include <gtest/gtest.h>
-#include "update_engine/common/libcurl_http_fetcher.h"
#include "update_engine/common/utils.h"
using std::string;
diff --git a/common/http_fetcher_unittest.cc b/common/http_fetcher_unittest.cc
index 6f3e480..0f34475 100644
--- a/common/http_fetcher_unittest.cc
+++ b/common/http_fetcher_unittest.cc
@@ -44,11 +44,11 @@
#include "update_engine/common/fake_hardware.h"
#include "update_engine/common/file_fetcher.h"
#include "update_engine/common/http_common.h"
-#include "update_engine/common/libcurl_http_fetcher.h"
#include "update_engine/common/mock_http_fetcher.h"
#include "update_engine/common/multi_range_http_fetcher.h"
#include "update_engine/common/test_utils.h"
#include "update_engine/common/utils.h"
+#include "update_engine/libcurl_http_fetcher.h"
#include "update_engine/mock_proxy_resolver.h"
#include "update_engine/proxy_resolver.h"
diff --git a/common/libcurl_http_fetcher.cc b/common/libcurl_http_fetcher.cc
deleted file mode 100644
index a222139..0000000
--- a/common/libcurl_http_fetcher.cc
+++ /dev/null
@@ -1,697 +0,0 @@
-//
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include "update_engine/common/libcurl_http_fetcher.h"
-
-#include <algorithm>
-#include <string>
-
-#include <base/bind.h>
-#include <base/format_macros.h>
-#include <base/location.h>
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-
-#include "update_engine/common/certificate_checker.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/platform_constants.h"
-
-using base::TimeDelta;
-using brillo::MessageLoop;
-using std::max;
-using std::string;
-
-// This is a concrete implementation of HttpFetcher that uses libcurl to do the
-// http work.
-
-namespace chromeos_update_engine {
-
-namespace {
-const int kNoNetworkRetrySeconds = 10;
-} // namespace
-
-LibcurlHttpFetcher::LibcurlHttpFetcher(ProxyResolver* proxy_resolver,
- HardwareInterface* hardware)
- : HttpFetcher(proxy_resolver), hardware_(hardware) {
- // Dev users want a longer timeout (180 seconds) because they may
- // be waiting on the dev server to build an image.
- if (!hardware_->IsOfficialBuild())
- low_speed_time_seconds_ = kDownloadDevModeLowSpeedTimeSeconds;
- if (hardware_->IsOOBEEnabled() && !hardware_->IsOOBEComplete(nullptr))
- max_retry_count_ = kDownloadMaxRetryCountOobeNotComplete;
-}
-
-LibcurlHttpFetcher::~LibcurlHttpFetcher() {
- LOG_IF(ERROR, transfer_in_progress_)
- << "Destroying the fetcher while a transfer is in progress.";
- CleanUp();
-}
-
-bool LibcurlHttpFetcher::GetProxyType(const string& proxy,
- curl_proxytype* out_type) {
- if (base::StartsWith(
- proxy, "socks5://", base::CompareCase::INSENSITIVE_ASCII) ||
- base::StartsWith(
- proxy, "socks://", base::CompareCase::INSENSITIVE_ASCII)) {
- *out_type = CURLPROXY_SOCKS5_HOSTNAME;
- return true;
- }
- if (base::StartsWith(
- proxy, "socks4://", base::CompareCase::INSENSITIVE_ASCII)) {
- *out_type = CURLPROXY_SOCKS4A;
- return true;
- }
- if (base::StartsWith(
- proxy, "http://", base::CompareCase::INSENSITIVE_ASCII) ||
- base::StartsWith(
- proxy, "https://", base::CompareCase::INSENSITIVE_ASCII)) {
- *out_type = CURLPROXY_HTTP;
- return true;
- }
- if (base::StartsWith(proxy, kNoProxy, base::CompareCase::INSENSITIVE_ASCII)) {
- // known failure case. don't log.
- return false;
- }
- LOG(INFO) << "Unknown proxy type: " << proxy;
- return false;
-}
-
-void LibcurlHttpFetcher::ResumeTransfer(const string& url) {
- LOG(INFO) << "Starting/Resuming transfer";
- CHECK(!transfer_in_progress_);
- url_ = url;
- curl_multi_handle_ = curl_multi_init();
- CHECK(curl_multi_handle_);
-
- curl_handle_ = curl_easy_init();
- CHECK(curl_handle_);
- ignore_failure_ = false;
-
- CHECK(HasProxy());
- bool is_direct = (GetCurrentProxy() == kNoProxy);
- LOG(INFO) << "Using proxy: " << (is_direct ? "no" : "yes");
- if (is_direct) {
- CHECK_EQ(curl_easy_setopt(curl_handle_,
- CURLOPT_PROXY,
- ""), CURLE_OK);
- } else {
- CHECK_EQ(curl_easy_setopt(curl_handle_,
- CURLOPT_PROXY,
- GetCurrentProxy().c_str()), CURLE_OK);
- // Curl seems to require us to set the protocol
- curl_proxytype type;
- if (GetProxyType(GetCurrentProxy(), &type)) {
- CHECK_EQ(curl_easy_setopt(curl_handle_,
- CURLOPT_PROXYTYPE,
- type), CURLE_OK);
- }
- }
-
- if (post_data_set_) {
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POST, 1), CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDS,
- post_data_.data()),
- CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDSIZE,
- post_data_.size()),
- CURLE_OK);
- }
-
- // Setup extra HTTP headers.
- if (curl_http_headers_) {
- curl_slist_free_all(curl_http_headers_);
- curl_http_headers_ = nullptr;
- }
- for (const auto& header : extra_headers_) {
- // curl_slist_append() copies the string.
- curl_http_headers_ =
- curl_slist_append(curl_http_headers_, header.second.c_str());
- }
- if (post_data_set_) {
- // Set the Content-Type HTTP header, if one was specifically set.
- if (post_content_type_ != kHttpContentTypeUnspecified) {
- const string content_type_attr = base::StringPrintf(
- "Content-Type: %s", GetHttpContentTypeString(post_content_type_));
- curl_http_headers_ =
- curl_slist_append(curl_http_headers_, content_type_attr.c_str());
- } else {
- LOG(WARNING) << "no content type set, using libcurl default";
- }
- }
- CHECK_EQ(
- curl_easy_setopt(curl_handle_, CURLOPT_HTTPHEADER, curl_http_headers_),
- CURLE_OK);
-
- if (bytes_downloaded_ > 0 || download_length_) {
- // Resume from where we left off.
- resume_offset_ = bytes_downloaded_;
- CHECK_GE(resume_offset_, 0);
-
- // Compute end offset, if one is specified. As per HTTP specification, this
- // is an inclusive boundary. Make sure it doesn't overflow.
- size_t end_offset = 0;
- if (download_length_) {
- end_offset = static_cast<size_t>(resume_offset_) + download_length_ - 1;
- CHECK_LE((size_t) resume_offset_, end_offset);
- }
-
- // Create a string representation of the desired range.
- string range_str = base::StringPrintf(
- "%" PRIu64 "-", static_cast<uint64_t>(resume_offset_));
- if (end_offset)
- range_str += std::to_string(end_offset);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_RANGE, range_str.c_str()),
- CURLE_OK);
- }
-
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_WRITEDATA, this), CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_WRITEFUNCTION,
- StaticLibcurlWrite), CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_URL, url_.c_str()),
- CURLE_OK);
-
- // If the connection drops under |low_speed_limit_bps_| (10
- // bytes/sec by default) for |low_speed_time_seconds_| (90 seconds,
- // 180 on non-official builds), reconnect.
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_LOW_SPEED_LIMIT,
- low_speed_limit_bps_),
- CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_LOW_SPEED_TIME,
- low_speed_time_seconds_),
- CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_CONNECTTIMEOUT,
- connect_timeout_seconds_),
- CURLE_OK);
-
- // By default, libcurl doesn't follow redirections. Allow up to
- // |kDownloadMaxRedirects| redirections.
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_FOLLOWLOCATION, 1), CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_MAXREDIRS,
- kDownloadMaxRedirects),
- CURLE_OK);
-
- // Lock down the appropriate curl options for HTTP or HTTPS depending on
- // the url.
- if (hardware_->IsOfficialBuild()) {
- if (base::StartsWith(
- url_, "http://", base::CompareCase::INSENSITIVE_ASCII)) {
- SetCurlOptionsForHttp();
- } else if (base::StartsWith(
- url_, "https://", base::CompareCase::INSENSITIVE_ASCII)) {
- SetCurlOptionsForHttps();
-#if !defined(__CHROMEOS__) && !defined(__BRILLO__)
- } else if (base::StartsWith(
- url_, "file://", base::CompareCase::INSENSITIVE_ASCII)) {
- SetCurlOptionsForFile();
-#endif
- } else {
- LOG(ERROR) << "Received invalid URI: " << url_;
- // Lock down to no protocol supported for the transfer.
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_PROTOCOLS, 0), CURLE_OK);
- }
- } else {
- LOG(INFO) << "Not setting http(s) curl options because we are "
- << "running a dev/test image";
- }
-
- CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK);
- transfer_in_progress_ = true;
-}
-
-// Lock down only the protocol in case of HTTP.
-void LibcurlHttpFetcher::SetCurlOptionsForHttp() {
- LOG(INFO) << "Setting up curl options for HTTP";
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_PROTOCOLS, CURLPROTO_HTTP),
- CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_REDIR_PROTOCOLS,
- CURLPROTO_HTTP),
- CURLE_OK);
-}
-
-// Security lock-down in official builds: makes sure that peer certificate
-// verification is enabled, restricts the set of trusted certificates,
-// restricts protocols to HTTPS, restricts ciphers to HIGH.
-void LibcurlHttpFetcher::SetCurlOptionsForHttps() {
- LOG(INFO) << "Setting up curl options for HTTPS";
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_SSL_VERIFYPEER, 1),
- CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_SSL_VERIFYHOST, 2),
- CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_CAPATH,
- constants::kCACertificatesPath),
- CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS),
- CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_REDIR_PROTOCOLS,
- CURLPROTO_HTTPS),
- CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_SSL_CIPHER_LIST, "HIGH:!ADH"),
- CURLE_OK);
- if (server_to_check_ != ServerToCheck::kNone) {
- CHECK_EQ(
- curl_easy_setopt(curl_handle_, CURLOPT_SSL_CTX_DATA, &server_to_check_),
- CURLE_OK);
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_SSL_CTX_FUNCTION,
- CertificateChecker::ProcessSSLContext),
- CURLE_OK);
- }
-}
-
-// Lock down only the protocol in case of a local file.
-void LibcurlHttpFetcher::SetCurlOptionsForFile() {
- LOG(INFO) << "Setting up curl options for FILE";
- CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_PROTOCOLS, CURLPROTO_FILE),
- CURLE_OK);
- CHECK_EQ(
- curl_easy_setopt(curl_handle_, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_FILE),
- CURLE_OK);
-}
-
-// Begins the transfer, which must not have already been started.
-void LibcurlHttpFetcher::BeginTransfer(const string& url) {
- CHECK(!transfer_in_progress_);
- url_ = url;
- auto closure = base::Bind(&LibcurlHttpFetcher::ProxiesResolved,
- base::Unretained(this));
- if (!ResolveProxiesForUrl(url_, closure)) {
- LOG(ERROR) << "Couldn't resolve proxies";
- if (delegate_)
- delegate_->TransferComplete(this, false);
- }
-}
-
-void LibcurlHttpFetcher::ProxiesResolved() {
- transfer_size_ = -1;
- resume_offset_ = 0;
- retry_count_ = 0;
- no_network_retry_count_ = 0;
- http_response_code_ = 0;
- terminate_requested_ = false;
- sent_byte_ = false;
-
- // If we are paused, we delay these two operations until Unpause is called.
- if (transfer_paused_) {
- restart_transfer_on_unpause_ = true;
- return;
- }
- ResumeTransfer(url_);
- CurlPerformOnce();
-}
-
-void LibcurlHttpFetcher::ForceTransferTermination() {
- CleanUp();
- if (delegate_) {
- // Note that after the callback returns this object may be destroyed.
- delegate_->TransferTerminated(this);
- }
-}
-
-void LibcurlHttpFetcher::TerminateTransfer() {
- if (in_write_callback_) {
- terminate_requested_ = true;
- } else {
- ForceTransferTermination();
- }
-}
-
-void LibcurlHttpFetcher::SetHeader(const string& header_name,
- const string& header_value) {
- string header_line = header_name + ": " + header_value;
- // Avoid the space if no data on the right side of the semicolon.
- if (header_value.empty())
- header_line = header_name + ":";
- TEST_AND_RETURN(header_line.find('\n') == string::npos);
- TEST_AND_RETURN(header_name.find(':') == string::npos);
- extra_headers_[base::ToLowerASCII(header_name)] = header_line;
-}
-
-void LibcurlHttpFetcher::CurlPerformOnce() {
- CHECK(transfer_in_progress_);
- int running_handles = 0;
- CURLMcode retcode = CURLM_CALL_MULTI_PERFORM;
-
- // libcurl may request that we immediately call curl_multi_perform after it
- // returns, so we do. libcurl promises that curl_multi_perform will not block.
- while (CURLM_CALL_MULTI_PERFORM == retcode) {
- retcode = curl_multi_perform(curl_multi_handle_, &running_handles);
- if (terminate_requested_) {
- ForceTransferTermination();
- return;
- }
- }
-
- // If the transfer completes while paused, we should ignore the failure once
- // the fetcher is unpaused.
- if (running_handles == 0 && transfer_paused_ && !ignore_failure_) {
- LOG(INFO) << "Connection closed while paused, ignoring failure.";
- ignore_failure_ = true;
- }
-
- if (running_handles != 0 || transfer_paused_) {
- // There's either more work to do or we are paused, so we just keep the
- // file descriptors to watch up to date and exit, until we are done with the
- // work and we are not paused.
- SetupMessageLoopSources();
- return;
- }
-
- // At this point, the transfer was completed in some way (error, connection
- // closed or download finished).
-
- GetHttpResponseCode();
- if (http_response_code_) {
- LOG(INFO) << "HTTP response code: " << http_response_code_;
- no_network_retry_count_ = 0;
- } else {
- LOG(ERROR) << "Unable to get http response code.";
- }
-
- // we're done!
- CleanUp();
-
- // TODO(petkov): This temporary code tries to deal with the case where the
- // update engine performs an update check while the network is not ready
- // (e.g., right after resume). Longer term, we should check if the network
- // is online/offline and return an appropriate error code.
- if (!sent_byte_ &&
- http_response_code_ == 0 &&
- no_network_retry_count_ < no_network_max_retries_) {
- no_network_retry_count_++;
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback,
- base::Unretained(this)),
- TimeDelta::FromSeconds(kNoNetworkRetrySeconds));
- LOG(INFO) << "No HTTP response, retry " << no_network_retry_count_;
- } else if ((!sent_byte_ && !IsHttpResponseSuccess()) ||
- IsHttpResponseError()) {
- // The transfer completed w/ error and we didn't get any bytes.
- // If we have another proxy to try, try that.
- //
- // TODO(garnold) in fact there are two separate cases here: one case is an
- // other-than-success return code (including no return code) and no
- // received bytes, which is necessary due to the way callbacks are
- // currently processing error conditions; the second is an explicit HTTP
- // error code, where some data may have been received (as in the case of a
- // semi-successful multi-chunk fetch). This is a confusing behavior and
- // should be unified into a complete, coherent interface.
- LOG(INFO) << "Transfer resulted in an error (" << http_response_code_
- << "), " << bytes_downloaded_ << " bytes downloaded";
-
- PopProxy(); // Delete the proxy we just gave up on.
-
- if (HasProxy()) {
- // We have another proxy. Retry immediately.
- LOG(INFO) << "Retrying with next proxy setting";
- MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback,
- base::Unretained(this)));
- } else {
- // Out of proxies. Give up.
- LOG(INFO) << "No further proxies, indicating transfer complete";
- if (delegate_)
- delegate_->TransferComplete(this, false); // signal fail
- return;
- }
- } else if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) {
- if (!ignore_failure_)
- retry_count_++;
- LOG(INFO) << "Transfer interrupted after downloading "
- << bytes_downloaded_ << " of " << transfer_size_ << " bytes. "
- << transfer_size_ - bytes_downloaded_ << " bytes remaining "
- << "after " << retry_count_ << " attempt(s)";
-
- if (retry_count_ > max_retry_count_) {
- LOG(INFO) << "Reached max attempts (" << retry_count_ << ")";
- if (delegate_)
- delegate_->TransferComplete(this, false); // signal fail
- return;
- }
- // Need to restart transfer
- LOG(INFO) << "Restarting transfer to download the remaining bytes";
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback,
- base::Unretained(this)),
- TimeDelta::FromSeconds(retry_seconds_));
- } else {
- LOG(INFO) << "Transfer completed (" << http_response_code_
- << "), " << bytes_downloaded_ << " bytes downloaded";
- if (delegate_) {
- bool success = IsHttpResponseSuccess();
- delegate_->TransferComplete(this, success);
- }
- return;
- }
- // If we reach this point is because TransferComplete() was not called in any
- // of the previous branches. The delegate is allowed to destroy the object
- // once TransferComplete is called so this would be illegal.
- ignore_failure_ = false;
-}
-
-size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) {
- // Update HTTP response first.
- GetHttpResponseCode();
- const size_t payload_size = size * nmemb;
-
- // Do nothing if no payload or HTTP response is an error.
- if (payload_size == 0 || !IsHttpResponseSuccess()) {
- LOG(INFO) << "HTTP response unsuccessful (" << http_response_code_
- << ") or no payload (" << payload_size << "), nothing to do";
- return 0;
- }
-
- sent_byte_ = true;
- {
- double transfer_size_double;
- CHECK_EQ(curl_easy_getinfo(curl_handle_,
- CURLINFO_CONTENT_LENGTH_DOWNLOAD,
- &transfer_size_double), CURLE_OK);
- off_t new_transfer_size = static_cast<off_t>(transfer_size_double);
- if (new_transfer_size > 0) {
- transfer_size_ = resume_offset_ + new_transfer_size;
- }
- }
- bytes_downloaded_ += payload_size;
- in_write_callback_ = true;
- if (delegate_)
- delegate_->ReceivedBytes(this, ptr, payload_size);
- in_write_callback_ = false;
- return payload_size;
-}
-
-void LibcurlHttpFetcher::Pause() {
- if (transfer_paused_) {
- LOG(ERROR) << "Fetcher already paused.";
- return;
- }
- transfer_paused_ = true;
- if (!transfer_in_progress_) {
- // If pause before we started a connection, we don't need to notify curl
- // about that, we will simply not start the connection later.
- return;
- }
- CHECK(curl_handle_);
- CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_ALL), CURLE_OK);
-}
-
-void LibcurlHttpFetcher::Unpause() {
- if (!transfer_paused_) {
- LOG(ERROR) << "Resume attempted when fetcher not paused.";
- return;
- }
- transfer_paused_ = false;
- if (restart_transfer_on_unpause_) {
- restart_transfer_on_unpause_ = false;
- ResumeTransfer(url_);
- CurlPerformOnce();
- return;
- }
- if (!transfer_in_progress_) {
- // If resumed before starting the connection, there's no need to notify
- // anybody. We will simply start the connection once it is time.
- return;
- }
- CHECK(curl_handle_);
- CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_CONT), CURLE_OK);
- // Since the transfer is in progress, we need to dispatch a CurlPerformOnce()
- // now to let the connection continue, otherwise it would be called by the
- // TimeoutCallback but with a delay.
- CurlPerformOnce();
-}
-
-// This method sets up callbacks with the MessageLoop.
-void LibcurlHttpFetcher::SetupMessageLoopSources() {
- fd_set fd_read;
- fd_set fd_write;
- fd_set fd_exc;
-
- FD_ZERO(&fd_read);
- FD_ZERO(&fd_write);
- FD_ZERO(&fd_exc);
-
- int fd_max = 0;
-
- // Ask libcurl for the set of file descriptors we should track on its
- // behalf.
- CHECK_EQ(curl_multi_fdset(curl_multi_handle_, &fd_read, &fd_write,
- &fd_exc, &fd_max), CURLM_OK);
-
- // We should iterate through all file descriptors up to libcurl's fd_max or
- // the highest one we're tracking, whichever is larger.
- for (size_t t = 0; t < arraysize(fd_task_maps_); ++t) {
- if (!fd_task_maps_[t].empty())
- fd_max = max(fd_max, fd_task_maps_[t].rbegin()->first);
- }
-
- // For each fd, if we're not tracking it, track it. If we are tracking it, but
- // libcurl doesn't care about it anymore, stop tracking it. After this loop,
- // there should be exactly as many tasks scheduled in fd_task_maps_[0|1] as
- // there are read/write fds that we're tracking.
- for (int fd = 0; fd <= fd_max; ++fd) {
- // Note that fd_exc is unused in the current version of libcurl so is_exc
- // should always be false.
- bool is_exc = FD_ISSET(fd, &fd_exc) != 0;
- bool must_track[2] = {
- is_exc || (FD_ISSET(fd, &fd_read) != 0), // track 0 -- read
- is_exc || (FD_ISSET(fd, &fd_write) != 0) // track 1 -- write
- };
- MessageLoop::WatchMode watch_modes[2] = {
- MessageLoop::WatchMode::kWatchRead,
- MessageLoop::WatchMode::kWatchWrite,
- };
-
- for (size_t t = 0; t < arraysize(fd_task_maps_); ++t) {
- auto fd_task_it = fd_task_maps_[t].find(fd);
- bool tracked = fd_task_it != fd_task_maps_[t].end();
-
- if (!must_track[t]) {
- // If we have an outstanding io_channel, remove it.
- if (tracked) {
- MessageLoop::current()->CancelTask(fd_task_it->second);
- fd_task_maps_[t].erase(fd_task_it);
- }
- continue;
- }
-
- // If we are already tracking this fd, continue -- nothing to do.
- if (tracked)
- continue;
-
- // Track a new fd.
- fd_task_maps_[t][fd] = MessageLoop::current()->WatchFileDescriptor(
- FROM_HERE,
- fd,
- watch_modes[t],
- true, // persistent
- base::Bind(&LibcurlHttpFetcher::CurlPerformOnce,
- base::Unretained(this)));
-
- static int io_counter = 0;
- io_counter++;
- if (io_counter % 50 == 0) {
- LOG(INFO) << "io_counter = " << io_counter;
- }
- }
- }
-
- // Set up a timeout callback for libcurl.
- if (timeout_id_ == MessageLoop::kTaskIdNull) {
- VLOG(1) << "Setting up timeout source: " << idle_seconds_ << " seconds.";
- timeout_id_ = MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&LibcurlHttpFetcher::TimeoutCallback,
- base::Unretained(this)),
- TimeDelta::FromSeconds(idle_seconds_));
- }
-}
-
-void LibcurlHttpFetcher::RetryTimeoutCallback() {
- if (transfer_paused_) {
- restart_transfer_on_unpause_ = true;
- return;
- }
- ResumeTransfer(url_);
- CurlPerformOnce();
-}
-
-void LibcurlHttpFetcher::TimeoutCallback() {
- // We always re-schedule the callback, even if we don't want to be called
- // anymore. We will remove the event source separately if we don't want to
- // be called back.
- timeout_id_ = MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&LibcurlHttpFetcher::TimeoutCallback, base::Unretained(this)),
- TimeDelta::FromSeconds(idle_seconds_));
-
- // CurlPerformOnce() may call CleanUp(), so we need to schedule our callback
- // first, since it could be canceled by this call.
- if (transfer_in_progress_)
- CurlPerformOnce();
-}
-
-void LibcurlHttpFetcher::CleanUp() {
- MessageLoop::current()->CancelTask(timeout_id_);
- timeout_id_ = MessageLoop::kTaskIdNull;
-
- for (size_t t = 0; t < arraysize(fd_task_maps_); ++t) {
- for (const auto& fd_taks_pair : fd_task_maps_[t]) {
- if (!MessageLoop::current()->CancelTask(fd_taks_pair.second)) {
- LOG(WARNING) << "Error canceling the watch task "
- << fd_taks_pair.second << " for "
- << (t ? "writing" : "reading") << " the fd "
- << fd_taks_pair.first;
- }
- }
- fd_task_maps_[t].clear();
- }
-
- if (curl_http_headers_) {
- curl_slist_free_all(curl_http_headers_);
- curl_http_headers_ = nullptr;
- }
- if (curl_handle_) {
- if (curl_multi_handle_) {
- CHECK_EQ(curl_multi_remove_handle(curl_multi_handle_, curl_handle_),
- CURLM_OK);
- }
- curl_easy_cleanup(curl_handle_);
- curl_handle_ = nullptr;
- }
- if (curl_multi_handle_) {
- CHECK_EQ(curl_multi_cleanup(curl_multi_handle_), CURLM_OK);
- curl_multi_handle_ = nullptr;
- }
- transfer_in_progress_ = false;
- transfer_paused_ = false;
- restart_transfer_on_unpause_ = false;
-}
-
-void LibcurlHttpFetcher::GetHttpResponseCode() {
- long http_response_code = 0; // NOLINT(runtime/int) - curl needs long.
- if (base::StartsWith(url_, "file://", base::CompareCase::INSENSITIVE_ASCII)) {
- // Fake out a valid response code for file:// URLs.
- http_response_code_ = 299;
- } else if (curl_easy_getinfo(curl_handle_,
- CURLINFO_RESPONSE_CODE,
- &http_response_code) == CURLE_OK) {
- http_response_code_ = static_cast<int>(http_response_code);
- }
-}
-
-} // namespace chromeos_update_engine
diff --git a/common/libcurl_http_fetcher.h b/common/libcurl_http_fetcher.h
deleted file mode 100644
index 7101aaa..0000000
--- a/common/libcurl_http_fetcher.h
+++ /dev/null
@@ -1,268 +0,0 @@
-//
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#ifndef UPDATE_ENGINE_COMMON_LIBCURL_HTTP_FETCHER_H_
-#define UPDATE_ENGINE_COMMON_LIBCURL_HTTP_FETCHER_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include <curl/curl.h>
-
-#include <base/logging.h>
-#include <base/macros.h>
-#include <brillo/message_loops/message_loop.h>
-
-#include "update_engine/common/certificate_checker.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/http_fetcher.h"
-
-// This is a concrete implementation of HttpFetcher that uses libcurl to do the
-// http work.
-
-namespace chromeos_update_engine {
-
-class LibcurlHttpFetcher : public HttpFetcher {
- public:
- LibcurlHttpFetcher(ProxyResolver* proxy_resolver,
- HardwareInterface* hardware);
-
- // Cleans up all internal state. Does not notify delegate
- ~LibcurlHttpFetcher() override;
-
- void SetOffset(off_t offset) override { bytes_downloaded_ = offset; }
-
- void SetLength(size_t length) override { download_length_ = length; }
- void UnsetLength() override { SetLength(0); }
-
- // Begins the transfer if it hasn't already begun.
- void BeginTransfer(const std::string& url) override;
-
- // If the transfer is in progress, aborts the transfer early. The transfer
- // cannot be resumed.
- void TerminateTransfer() override;
-
- // Pass the headers to libcurl.
- void SetHeader(const std::string& header_name,
- const std::string& header_value) override;
-
- // Suspend the transfer by calling curl_easy_pause(CURLPAUSE_ALL).
- void Pause() override;
-
- // Resume the transfer by calling curl_easy_pause(CURLPAUSE_CONT).
- void Unpause() override;
-
- // Libcurl sometimes asks to be called back after some time while
- // leaving that time unspecified. In that case, we pick a reasonable
- // default of one second, but it can be overridden here. This is
- // primarily useful for testing.
- // From http://curl.haxx.se/libcurl/c/curl_multi_timeout.html:
- // if libcurl returns a -1 timeout here, it just means that libcurl
- // currently has no stored timeout value. You must not wait too long
- // (more than a few seconds perhaps) before you call
- // curl_multi_perform() again.
- void set_idle_seconds(int seconds) override { idle_seconds_ = seconds; }
-
- // Sets the retry timeout. Useful for testing.
- void set_retry_seconds(int seconds) override { retry_seconds_ = seconds; }
-
- void set_no_network_max_retries(int retries) {
- no_network_max_retries_ = retries;
- }
-
- void set_server_to_check(ServerToCheck server_to_check) {
- server_to_check_ = server_to_check;
- }
-
- size_t GetBytesDownloaded() override {
- return static_cast<size_t>(bytes_downloaded_);
- }
-
- void set_low_speed_limit(int low_speed_bps, int low_speed_sec) override {
- low_speed_limit_bps_ = low_speed_bps;
- low_speed_time_seconds_ = low_speed_sec;
- }
-
- void set_connect_timeout(int connect_timeout_seconds) override {
- connect_timeout_seconds_ = connect_timeout_seconds;
- }
-
- void set_max_retry_count(int max_retry_count) override {
- max_retry_count_ = max_retry_count;
- }
-
- private:
- // Callback for when proxy resolution has completed. This begins the
- // transfer.
- void ProxiesResolved();
-
- // Asks libcurl for the http response code and stores it in the object.
- void GetHttpResponseCode();
-
- // Checks whether stored HTTP response is within the success range.
- inline bool IsHttpResponseSuccess() {
- return (http_response_code_ >= 200 && http_response_code_ < 300);
- }
-
- // Checks whether stored HTTP response is within the error range. This
- // includes both errors with the request (4xx) and server errors (5xx).
- inline bool IsHttpResponseError() {
- return (http_response_code_ >= 400 && http_response_code_ < 600);
- }
-
- // Resumes a transfer where it left off. This will use the
- // HTTP Range: header to make a new connection from where the last
- // left off.
- virtual void ResumeTransfer(const std::string& url);
-
- void TimeoutCallback();
- void RetryTimeoutCallback();
-
- // Calls into curl_multi_perform to let libcurl do its work. Returns after
- // curl_multi_perform is finished, which may actually be after more than
- // one call to curl_multi_perform. This method will set up the message
- // loop with sources for future work that libcurl will do, if any, or complete
- // the transfer and finish the action if no work left to do.
- // This method will not block.
- void CurlPerformOnce();
-
- // Sets up message loop sources as needed by libcurl. This is generally
- // the file descriptor of the socket and a timer in case nothing happens
- // on the fds.
- void SetupMessageLoopSources();
-
- // Callback called by libcurl when new data has arrived on the transfer
- size_t LibcurlWrite(void *ptr, size_t size, size_t nmemb);
- static size_t StaticLibcurlWrite(void *ptr, size_t size,
- size_t nmemb, void *stream) {
- return reinterpret_cast<LibcurlHttpFetcher*>(stream)->
- LibcurlWrite(ptr, size, nmemb);
- }
-
- // Cleans up the following if they are non-null:
- // curl(m) handles, fd_task_maps_, timeout_id_.
- void CleanUp();
-
- // Force terminate the transfer. This will invoke the delegate's (if any)
- // TransferTerminated callback so, after returning, this fetcher instance may
- // be destroyed.
- void ForceTransferTermination();
-
- // Sets the curl options for HTTP URL.
- void SetCurlOptionsForHttp();
-
- // Sets the curl options for HTTPS URL.
- void SetCurlOptionsForHttps();
-
- // Sets the curl options for file URI.
- void SetCurlOptionsForFile();
-
- // Convert a proxy URL into a curl proxy type, if applicable. Returns true iff
- // conversion was successful, false otherwise (in which case nothing is
- // written to |out_type|).
- bool GetProxyType(const std::string& proxy, curl_proxytype* out_type);
-
- // Hardware interface used to query dev-mode and official build settings.
- HardwareInterface* hardware_;
-
- // Handles for the libcurl library
- CURLM* curl_multi_handle_{nullptr};
- CURL* curl_handle_{nullptr};
- struct curl_slist* curl_http_headers_{nullptr};
-
- // The extra headers that will be sent on each request.
- std::map<std::string, std::string> extra_headers_;
-
- // Lists of all read(0)/write(1) file descriptors that we're waiting on from
- // the message loop. libcurl may open/close descriptors and switch their
- // directions so maintain two separate lists so that watch conditions can be
- // set appropriately.
- std::map<int, brillo::MessageLoop::TaskId> fd_task_maps_[2];
-
- // The TaskId of the timer we're waiting on. kTaskIdNull if we are not waiting
- // on it.
- brillo::MessageLoop::TaskId timeout_id_{brillo::MessageLoop::kTaskIdNull};
-
- bool transfer_in_progress_{false};
- bool transfer_paused_{false};
-
- // Whether it should ignore transfer failures for the purpose of retrying the
- // connection.
- bool ignore_failure_{false};
-
- // Whether we should restart the transfer once Unpause() is called. This can
- // be caused because either the connection dropped while pause or the proxy
- // was resolved and we never started the transfer in the first place.
- bool restart_transfer_on_unpause_{false};
-
- // The transfer size. -1 if not known.
- off_t transfer_size_{0};
-
- // How many bytes have been downloaded and sent to the delegate.
- off_t bytes_downloaded_{0};
-
- // The remaining maximum number of bytes to download. Zero represents an
- // unspecified length.
- size_t download_length_{0};
-
- // If we resumed an earlier transfer, data offset that we used for the
- // new connection. 0 otherwise.
- // In this class, resume refers to resuming a dropped HTTP connection,
- // not to resuming an interrupted download.
- off_t resume_offset_{0};
-
- // Number of resumes performed so far and the max allowed.
- int retry_count_{0};
- int max_retry_count_{kDownloadMaxRetryCount};
-
- // Seconds to wait before retrying a resume.
- int retry_seconds_{20};
-
- // Number of resumes due to no network (e.g., HTTP response code 0).
- int no_network_retry_count_{0};
- int no_network_max_retries_{0};
-
- // Seconds to wait before asking libcurl to "perform".
- int idle_seconds_{1};
-
- // If true, we are currently performing a write callback on the delegate.
- bool in_write_callback_{false};
-
- // If true, we have returned at least one byte in the write callback
- // to the delegate.
- bool sent_byte_{false};
-
- // We can't clean everything up while we're in a write callback, so
- // if we get a terminate request, queue it until we can handle it.
- bool terminate_requested_{false};
-
- // The ServerToCheck used when checking this connection's certificate. If no
- // certificate check needs to be performed, this should be set to
- // ServerToCheck::kNone.
- ServerToCheck server_to_check_{ServerToCheck::kNone};
-
- int low_speed_limit_bps_{kDownloadLowSpeedLimitBps};
- int low_speed_time_seconds_{kDownloadLowSpeedTimeSeconds};
- int connect_timeout_seconds_{kDownloadConnectTimeoutSeconds};
-
- DISALLOW_COPY_AND_ASSIGN(LibcurlHttpFetcher);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_COMMON_LIBCURL_HTTP_FETCHER_H_
diff --git a/common/mock_certificate_checker.h b/common/mock_certificate_checker.h
deleted file mode 100644
index 1f55ca1..0000000
--- a/common/mock_certificate_checker.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// Copyright (C) 2011 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#ifndef UPDATE_ENGINE_COMMON_MOCK_CERTIFICATE_CHECKER_H_
-#define UPDATE_ENGINE_COMMON_MOCK_CERTIFICATE_CHECKER_H_
-
-#include <gmock/gmock.h>
-#include <openssl/ssl.h>
-
-#include "update_engine/common/certificate_checker.h"
-
-namespace chromeos_update_engine {
-
-class MockOpenSSLWrapper : public OpenSSLWrapper {
- public:
- MOCK_CONST_METHOD4(GetCertificateDigest,
- bool(X509_STORE_CTX* x509_ctx,
- int* out_depth,
- unsigned int* out_digest_length,
- uint8_t* out_digest));
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_COMMON_MOCK_CERTIFICATE_CHECKER_H_