1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2009 The Android Open Source Project 3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License"); 5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License. 6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at 7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// http://www.apache.org/licenses/LICENSE-2.0 9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software 11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS, 12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and 14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License. 15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 1649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 1739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/libcurl_http_fetcher.h" 18d57d1474a7bb152adf10d8c31d7ef6d40d27f7ccAndrew de los Reyes 19c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com#include <algorithm> 20d57d1474a7bb152adf10d8c31d7ef6d40d27f7ccAndrew de los Reyes#include <string> 21d57d1474a7bb152adf10d8c31d7ef6d40d27f7ccAndrew de los Reyes 224906c1c6dac2ef7916bfa7193cc9324e99b4d223Alex Vakulenko#include <base/bind.h> 23c00c98a1dad941e5cc04ce0b0e766d40b3b384e1Alex Deymo#include <base/format_macros.h> 2460ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo#include <base/location.h> 25d57d1474a7bb152adf10d8c31d7ef6d40d27f7ccAndrew de los Reyes#include <base/logging.h> 2675039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/string_util.h> 2775039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/stringprintf.h> 28d57d1474a7bb152adf10d8c31d7ef6d40d27f7ccAndrew de los Reyes 2939910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/certificate_checker.h" 3039910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/hardware_interface.h" 3139910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/platform_constants.h" 32c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com 3360ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymousing base::TimeDelta; 343f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenkousing brillo::MessageLoop; 35c4acdf40033fc7bedba3ec6449b7a750b1fe5f24Alex Deymousing std::max; 36d57d1474a7bb152adf10d8c31d7ef6d40d27f7ccAndrew de los Reyesusing std::string; 3749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 3849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com// This is a concrete implementation of HttpFetcher that uses libcurl to do the 3949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com// http work. 4049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 4149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.comnamespace chromeos_update_engine { 4249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 439bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyesnamespace { 445d0783d4a9dc230aebdf89923d31b51fe1def5f1Andrew de los Reyesconst int kNoNetworkRetrySeconds = 10; 45d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko} // namespace 469bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes 4733e91e78bfe98c063b0c3b6d590976e275685686Alex DeymoLibcurlHttpFetcher::LibcurlHttpFetcher(ProxyResolver* proxy_resolver, 4833e91e78bfe98c063b0c3b6d590976e275685686Alex Deymo HardwareInterface* hardware) 4933e91e78bfe98c063b0c3b6d590976e275685686Alex Deymo : HttpFetcher(proxy_resolver), hardware_(hardware) { 50c1c17b4ed6a3896b6343e737fd89682fa0c8436bAlex Deymo // Dev users want a longer timeout (180 seconds) because they may 51c1c17b4ed6a3896b6343e737fd89682fa0c8436bAlex Deymo // be waiting on the dev server to build an image. 52c1c17b4ed6a3896b6343e737fd89682fa0c8436bAlex Deymo if (!hardware_->IsOfficialBuild()) 53c1c17b4ed6a3896b6343e737fd89682fa0c8436bAlex Deymo low_speed_time_seconds_ = kDownloadDevModeLowSpeedTimeSeconds; 54c1c17b4ed6a3896b6343e737fd89682fa0c8436bAlex Deymo if (!hardware_->IsOOBEComplete(nullptr)) 55c1c17b4ed6a3896b6343e737fd89682fa0c8436bAlex Deymo max_retry_count_ = kDownloadMaxRetryCountOobeNotComplete; 56c1c17b4ed6a3896b6343e737fd89682fa0c8436bAlex Deymo} 57c1c17b4ed6a3896b6343e737fd89682fa0c8436bAlex Deymo 5849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.comLibcurlHttpFetcher::~LibcurlHttpFetcher() { 599ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov LOG_IF(ERROR, transfer_in_progress_) 609ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov << "Destroying the fetcher while a transfer is in progress."; 6149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CleanUp(); 6249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} 6349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 64f329b933db41d26644a97afef928eb1b319d6d99Alex Deymobool LibcurlHttpFetcher::GetProxyType(const string& proxy, 6559d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold curl_proxytype* out_type) { 6656ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo if (base::StartsWith( 6756ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo proxy, "socks5://", base::CompareCase::INSENSITIVE_ASCII) || 6856ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo base::StartsWith( 6956ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo proxy, "socks://", base::CompareCase::INSENSITIVE_ASCII)) { 7059d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold *out_type = CURLPROXY_SOCKS5_HOSTNAME; 7159d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold return true; 7259d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold } 7356ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo if (base::StartsWith( 7456ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo proxy, "socks4://", base::CompareCase::INSENSITIVE_ASCII)) { 7559d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold *out_type = CURLPROXY_SOCKS4A; 7659d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold return true; 7759d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold } 7856ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo if (base::StartsWith( 7956ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo proxy, "http://", base::CompareCase::INSENSITIVE_ASCII) || 8056ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo base::StartsWith( 8156ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo proxy, "https://", base::CompareCase::INSENSITIVE_ASCII)) { 8259d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold *out_type = CURLPROXY_HTTP; 8359d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold return true; 8459d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold } 8556ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo if (base::StartsWith(proxy, kNoProxy, base::CompareCase::INSENSITIVE_ASCII)) { 8659d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold // known failure case. don't log. 8759d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold return false; 8859d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold } 8959d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold LOG(INFO) << "Unknown proxy type: " << proxy; 9059d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold return false; 9159d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold} 9259d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold 93f329b933db41d26644a97afef928eb1b319d6d99Alex Deymovoid LibcurlHttpFetcher::ResumeTransfer(const string& url) { 943270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes LOG(INFO) << "Starting/Resuming transfer"; 9549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CHECK(!transfer_in_progress_); 9649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com url_ = url; 9749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com curl_multi_handle_ = curl_multi_init(); 9849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CHECK(curl_multi_handle_); 9949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 10049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com curl_handle_ = curl_easy_init(); 10149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CHECK(curl_handle_); 102f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo ignore_failure_ = false; 10349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 1044516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes CHECK(HasProxy()); 105fbaee24d80b2da982b81deca03702350e656f4b5Gilad Arnold bool is_direct = (GetCurrentProxy() == kNoProxy); 106fbaee24d80b2da982b81deca03702350e656f4b5Gilad Arnold LOG(INFO) << "Using proxy: " << (is_direct ? "no" : "yes"); 107fbaee24d80b2da982b81deca03702350e656f4b5Gilad Arnold if (is_direct) { 1084516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes CHECK_EQ(curl_easy_setopt(curl_handle_, 1094516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes CURLOPT_PROXY, 1104516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes ""), CURLE_OK); 1114516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes } else { 1124516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes CHECK_EQ(curl_easy_setopt(curl_handle_, 1134516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes CURLOPT_PROXY, 1144516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes GetCurrentProxy().c_str()), CURLE_OK); 1154516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes // Curl seems to require us to set the protocol 1164516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes curl_proxytype type; 11759d9e0142388f23dae84f7b480d24f1f71b80cfaGilad Arnold if (GetProxyType(GetCurrentProxy(), &type)) { 1184516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes CHECK_EQ(curl_easy_setopt(curl_handle_, 1194516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes CURLOPT_PROXYTYPE, 1204516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes type), CURLE_OK); 1214516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes } 1224516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes } 1234516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes 12449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com if (post_data_set_) { 125c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POST, 1), CURLE_OK); 126c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDS, 127f68bbbc952aa9a71898e4939b5f36187fa564a50Alex Vakulenko post_data_.data()), 128c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CURLE_OK); 129c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDSIZE, 130c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com post_data_.size()), 131c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CURLE_OK); 1326f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo } 1339dd1e7c6bbc605c2150800f763c596ff0a4ad1c1Gilad Arnold 1346f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo // Setup extra HTTP headers. 1356f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo if (curl_http_headers_) { 1366f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo curl_slist_free_all(curl_http_headers_); 1376f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo curl_http_headers_ = nullptr; 1386f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo } 1396f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo for (const auto& header : extra_headers_) { 1406f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo // curl_slist_append() copies the string. 1416f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo curl_http_headers_ = 1426f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo curl_slist_append(curl_http_headers_, header.second.c_str()); 1436f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo } 1446f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo if (post_data_set_) { 1459dd1e7c6bbc605c2150800f763c596ff0a4ad1c1Gilad Arnold // Set the Content-Type HTTP header, if one was specifically set. 1469dd1e7c6bbc605c2150800f763c596ff0a4ad1c1Gilad Arnold if (post_content_type_ != kHttpContentTypeUnspecified) { 1476f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo const string content_type_attr = base::StringPrintf( 1486f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo "Content-Type: %s", GetHttpContentTypeString(post_content_type_)); 1496f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo curl_http_headers_ = 1506f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo curl_slist_append(curl_http_headers_, content_type_attr.c_str()); 1519dd1e7c6bbc605c2150800f763c596ff0a4ad1c1Gilad Arnold } else { 1529dd1e7c6bbc605c2150800f763c596ff0a4ad1c1Gilad Arnold LOG(WARNING) << "no content type set, using libcurl default"; 1539dd1e7c6bbc605c2150800f763c596ff0a4ad1c1Gilad Arnold } 15449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 1556f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo CHECK_EQ( 1566f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo curl_easy_setopt(curl_handle_, CURLOPT_HTTPHEADER, curl_http_headers_), 1576f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo CURLE_OK); 15849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 159e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (bytes_downloaded_ > 0 || download_length_) { 160e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold // Resume from where we left off. 161c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com resume_offset_ = bytes_downloaded_; 162e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold CHECK_GE(resume_offset_, 0); 163e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold 164e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold // Compute end offset, if one is specified. As per HTTP specification, this 165e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold // is an inclusive boundary. Make sure it doesn't overflow. 166e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold size_t end_offset = 0; 167e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (download_length_) { 168e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold end_offset = static_cast<size_t>(resume_offset_) + download_length_ - 1; 169e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold CHECK_LE((size_t) resume_offset_, end_offset); 170e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold } 171e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold 172e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold // Create a string representation of the desired range. 173c00c98a1dad941e5cc04ce0b0e766d40b3b384e1Alex Deymo string range_str = base::StringPrintf( 174c00c98a1dad941e5cc04ce0b0e766d40b3b384e1Alex Deymo "%" PRIu64 "-", static_cast<uint64_t>(resume_offset_)); 175c00c98a1dad941e5cc04ce0b0e766d40b3b384e1Alex Deymo if (end_offset) 176c00c98a1dad941e5cc04ce0b0e766d40b3b384e1Alex Deymo range_str += std::to_string(end_offset); 177e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_RANGE, range_str.c_str()), 178e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold CURLE_OK); 179c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com } 180c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com 181c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_WRITEDATA, this), CURLE_OK); 182c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_WRITEFUNCTION, 183c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com StaticLibcurlWrite), CURLE_OK); 18477f79e876a77796fc248d099b6574f05bd23c954Chris Sosa CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_URL, url_.c_str()), 185d57d1474a7bb152adf10d8c31d7ef6d40d27f7ccAndrew de los Reyes CURLE_OK); 1863270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes 18734135a9f24c72137aa85378b57e7698162c687f2David Zeuthen // If the connection drops under |low_speed_limit_bps_| (10 18834135a9f24c72137aa85378b57e7698162c687f2David Zeuthen // bytes/sec by default) for |low_speed_time_seconds_| (90 seconds, 18934135a9f24c72137aa85378b57e7698162c687f2David Zeuthen // 180 on non-official builds), reconnect. 19034135a9f24c72137aa85378b57e7698162c687f2David Zeuthen CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_LOW_SPEED_LIMIT, 19134135a9f24c72137aa85378b57e7698162c687f2David Zeuthen low_speed_limit_bps_), 1923270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes CURLE_OK); 19334135a9f24c72137aa85378b57e7698162c687f2David Zeuthen CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_LOW_SPEED_TIME, 19434135a9f24c72137aa85378b57e7698162c687f2David Zeuthen low_speed_time_seconds_), 1953270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes CURLE_OK); 19634135a9f24c72137aa85378b57e7698162c687f2David Zeuthen CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_CONNECTTIMEOUT, 19734135a9f24c72137aa85378b57e7698162c687f2David Zeuthen connect_timeout_seconds_), 198e72f9c028fe41052cc18c95411fc1cd21d5029a3Andrew de los Reyes CURLE_OK); 1993270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes 20041c2fcf4525a3b4e8960c4b71dfe4f4f11c8224fDarin Petkov // By default, libcurl doesn't follow redirections. Allow up to 20134135a9f24c72137aa85378b57e7698162c687f2David Zeuthen // |kDownloadMaxRedirects| redirections. 2023a4016aefdf84b55ff04571fd005c7967efb243fDarin Petkov CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_FOLLOWLOCATION, 1), CURLE_OK); 20334135a9f24c72137aa85378b57e7698162c687f2David Zeuthen CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_MAXREDIRS, 20434135a9f24c72137aa85378b57e7698162c687f2David Zeuthen kDownloadMaxRedirects), 20541c2fcf4525a3b4e8960c4b71dfe4f4f11c8224fDarin Petkov CURLE_OK); 20641c2fcf4525a3b4e8960c4b71dfe4f4f11c8224fDarin Petkov 2077d623ebf9eee346fdeee71f1ccb32ebaf4bd3318Nam T. Nguyen // Lock down the appropriate curl options for HTTP or HTTPS depending on 2087d623ebf9eee346fdeee71f1ccb32ebaf4bd3318Nam T. Nguyen // the url. 209c1c17b4ed6a3896b6343e737fd89682fa0c8436bAlex Deymo if (hardware_->IsOfficialBuild()) { 21056ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo if (base::StartsWith( 21156ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo url_, "http://", base::CompareCase::INSENSITIVE_ASCII)) { 212b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan SetCurlOptionsForHttp(); 21356ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo } else if (base::StartsWith( 21456ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo url_, "https://", base::CompareCase::INSENSITIVE_ASCII)) { 215b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan SetCurlOptionsForHttps(); 21656ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo#if !defined(__CHROMEOS__) && !defined(__BRILLO__) 21756ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo } else if (base::StartsWith( 21856ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo url_, "file://", base::CompareCase::INSENSITIVE_ASCII)) { 21956ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo SetCurlOptionsForFile(); 22056ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo#endif 22156ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo } else { 22256ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo LOG(ERROR) << "Received invalid URI: " << url_; 22356ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo // Lock down to no protocol supported for the transfer. 22456ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_PROTOCOLS, 0), CURLE_OK); 22556ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo } 226b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan } else { 2277d623ebf9eee346fdeee71f1ccb32ebaf4bd3318Nam T. Nguyen LOG(INFO) << "Not setting http(s) curl options because we are " 2287d623ebf9eee346fdeee71f1ccb32ebaf4bd3318Nam T. Nguyen << "running a dev/test image"; 229fc7a0cec794ab43e66b6781ddb7f498b0ce257b9Darin Petkov } 230fc7a0cec794ab43e66b6781ddb7f498b0ce257b9Darin Petkov 231c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK); 23249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com transfer_in_progress_ = true; 23349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} 23449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 235b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan// Lock down only the protocol in case of HTTP. 236b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasanvoid LibcurlHttpFetcher::SetCurlOptionsForHttp() { 237b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan LOG(INFO) << "Setting up curl options for HTTP"; 238b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_PROTOCOLS, CURLPROTO_HTTP), 239b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CURLE_OK); 240b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_REDIR_PROTOCOLS, 241b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CURLPROTO_HTTP), 242b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CURLE_OK); 243b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan} 244b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan 245b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan// Security lock-down in official builds: makes sure that peer certificate 246b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan// verification is enabled, restricts the set of trusted certificates, 247b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan// restricts protocols to HTTPS, restricts ciphers to HIGH. 248b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasanvoid LibcurlHttpFetcher::SetCurlOptionsForHttps() { 249b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan LOG(INFO) << "Setting up curl options for HTTPS"; 250b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_SSL_VERIFYPEER, 1), 251b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CURLE_OK); 25235b3584ab4041aa32e1d049bd6ddff5941b03df2Alex Deymo CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_CAPATH, 25335b3584ab4041aa32e1d049bd6ddff5941b03df2Alex Deymo constants::kCACertificatesPath), 254b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CURLE_OK); 255b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS), 256b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CURLE_OK); 257b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_REDIR_PROTOCOLS, 258b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CURLPROTO_HTTPS), 259b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CURLE_OK); 260b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_SSL_CIPHER_LIST, "HIGH:!ADH"), 261b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CURLE_OK); 26233e91e78bfe98c063b0c3b6d590976e275685686Alex Deymo if (server_to_check_ != ServerToCheck::kNone) { 26333e91e78bfe98c063b0c3b6d590976e275685686Alex Deymo CHECK_EQ( 26433e91e78bfe98c063b0c3b6d590976e275685686Alex Deymo curl_easy_setopt(curl_handle_, CURLOPT_SSL_CTX_DATA, &server_to_check_), 26533e91e78bfe98c063b0c3b6d590976e275685686Alex Deymo CURLE_OK); 266b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_SSL_CTX_FUNCTION, 267b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CertificateChecker::ProcessSSLContext), 268b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan CURLE_OK); 269b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan } 270b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan} 271b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan 27256ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo// Lock down only the protocol in case of a local file. 27356ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymovoid LibcurlHttpFetcher::SetCurlOptionsForFile() { 27456ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo LOG(INFO) << "Setting up curl options for FILE"; 27556ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_PROTOCOLS, CURLPROTO_FILE), 27656ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo CURLE_OK); 27756ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo CHECK_EQ( 27856ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo curl_easy_setopt(curl_handle_, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_FILE), 27956ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo CURLE_OK); 28056ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo} 281b3f5540ee27bd53a28e3a3f87e2f5e80fb2a4876Jay Srinivasan 282c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com// Begins the transfer, which must not have already been started. 283f329b933db41d26644a97afef928eb1b319d6d99Alex Deymovoid LibcurlHttpFetcher::BeginTransfer(const string& url) { 284f3ed8e7d4ad456a3c841d8a530f308b6fcb2a4ccAndrew de los Reyes CHECK(!transfer_in_progress_); 285f3ed8e7d4ad456a3c841d8a530f308b6fcb2a4ccAndrew de los Reyes url_ = url; 2864906c1c6dac2ef7916bfa7193cc9324e99b4d223Alex Vakulenko auto closure = base::Bind(&LibcurlHttpFetcher::ProxiesResolved, 2874906c1c6dac2ef7916bfa7193cc9324e99b4d223Alex Vakulenko base::Unretained(this)); 28860ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo if (!ResolveProxiesForUrl(url_, closure)) { 289f3ed8e7d4ad456a3c841d8a530f308b6fcb2a4ccAndrew de los Reyes LOG(ERROR) << "Couldn't resolve proxies"; 290f3ed8e7d4ad456a3c841d8a530f308b6fcb2a4ccAndrew de los Reyes if (delegate_) 291f3ed8e7d4ad456a3c841d8a530f308b6fcb2a4ccAndrew de los Reyes delegate_->TransferComplete(this, false); 292f3ed8e7d4ad456a3c841d8a530f308b6fcb2a4ccAndrew de los Reyes } 293f3ed8e7d4ad456a3c841d8a530f308b6fcb2a4ccAndrew de los Reyes} 294f3ed8e7d4ad456a3c841d8a530f308b6fcb2a4ccAndrew de los Reyes 295f3ed8e7d4ad456a3c841d8a530f308b6fcb2a4ccAndrew de los Reyesvoid LibcurlHttpFetcher::ProxiesResolved() { 296c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com transfer_size_ = -1; 297c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com resume_offset_ = 0; 2989bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes retry_count_ = 0; 299a092955cdf763260563a774f6a68e1bfb38c5a8bDarin Petkov no_network_retry_count_ = 0; 300cb466212cccca21dfe0dcd01afbbb06e005309e2Darin Petkov http_response_code_ = 0; 301819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes terminate_requested_ = false; 302a2dee1d3a7f13c91b6d4973dca477c5496e9cf53Gilad Arnold sent_byte_ = false; 303f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo 304f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // If we are paused, we delay these two operations until Unpause is called. 305f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (transfer_paused_) { 306f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo restart_transfer_on_unpause_ = true; 307f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo return; 308f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 309f3ed8e7d4ad456a3c841d8a530f308b6fcb2a4ccAndrew de los Reyes ResumeTransfer(url_); 3109bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes CurlPerformOnce(); 311c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com} 312c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com 3139ce452b6acd95899e9adb17c2935012625163dc6Darin Petkovvoid LibcurlHttpFetcher::ForceTransferTermination() { 3149ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov CleanUp(); 3159ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov if (delegate_) { 3169ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov // Note that after the callback returns this object may be destroyed. 3179ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov delegate_->TransferTerminated(this); 3189ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov } 3199ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov} 3209ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov 32149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.comvoid LibcurlHttpFetcher::TerminateTransfer() { 3229ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov if (in_write_callback_) { 3233fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyes terminate_requested_ = true; 3249ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov } else { 3259ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov ForceTransferTermination(); 3269ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov } 32749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} 32849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 3296f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymovoid LibcurlHttpFetcher::SetHeader(const string& header_name, 3306f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo const string& header_value) { 3316f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo string header_line = header_name + ": " + header_value; 3326f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo // Avoid the space if no data on the right side of the semicolon. 3336f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo if (header_value.empty()) 3346f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo header_line = header_name + ":"; 3356f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo TEST_AND_RETURN(header_line.find('\n') == string::npos); 3366f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo TEST_AND_RETURN(header_name.find(':') == string::npos); 3376f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo extra_headers_[base::ToLowerASCII(header_name)] = header_line; 3386f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo} 3396f10c5f7c550b1bd6df1d9a04b5e75e03f943639Alex Deymo 340cb319330c529b0394f6efb416dbe7b03bf38b19bAndrew de los Reyesvoid LibcurlHttpFetcher::CurlPerformOnce() { 34149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CHECK(transfer_in_progress_); 34249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com int running_handles = 0; 34349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CURLMcode retcode = CURLM_CALL_MULTI_PERFORM; 34449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 34549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // libcurl may request that we immediately call curl_multi_perform after it 34649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // returns, so we do. libcurl promises that curl_multi_perform will not block. 34749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com while (CURLM_CALL_MULTI_PERFORM == retcode) { 34849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com retcode = curl_multi_perform(curl_multi_handle_, &running_handles); 3493fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyes if (terminate_requested_) { 3509ce452b6acd95899e9adb17c2935012625163dc6Darin Petkov ForceTransferTermination(); 3513fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyes return; 3523fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyes } 35349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 354192ced474a4226f1921fcdaa6a763f5f2d7e1b49Darin Petkov 355f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // If the transfer completes while paused, we should ignore the failure once 356f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // the fetcher is unpaused. 357f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (running_handles == 0 && transfer_paused_ && !ignore_failure_) { 358f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(INFO) << "Connection closed while paused, ignoring failure."; 359f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo ignore_failure_ = true; 360f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 361f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo 362f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (running_handles != 0 || transfer_paused_) { 363f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // There's either more work to do or we are paused, so we just keep the 364f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // file descriptors to watch up to date and exit, until we are done with the 365f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // work and we are not paused. 366f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo SetupMessageLoopSources(); 367f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo return; 368f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 369f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo 370f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // At this point, the transfer was completed in some way (error, connection 371f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // closed or download finished). 372f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo 373f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo GetHttpResponseCode(); 374f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (http_response_code_) { 375f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(INFO) << "HTTP response code: " << http_response_code_; 376f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo no_network_retry_count_ = 0; 377f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } else { 378f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(ERROR) << "Unable to get http response code."; 379f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 380f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo 381f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // we're done! 382f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo CleanUp(); 383f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo 384f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // TODO(petkov): This temporary code tries to deal with the case where the 385f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // update engine performs an update check while the network is not ready 386f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // (e.g., right after resume). Longer term, we should check if the network 387f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // is online/offline and return an appropriate error code. 388f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (!sent_byte_ && 389f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo http_response_code_ == 0 && 390f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo no_network_retry_count_ < no_network_max_retries_) { 391f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo no_network_retry_count_++; 392f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo MessageLoop::current()->PostDelayedTask( 393f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo FROM_HERE, 394f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback, 395f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo base::Unretained(this)), 396f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo TimeDelta::FromSeconds(kNoNetworkRetrySeconds)); 397f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(INFO) << "No HTTP response, retry " << no_network_retry_count_; 398f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } else if ((!sent_byte_ && !IsHttpResponseSuccess()) || 399f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo IsHttpResponseError()) { 400f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // The transfer completed w/ error and we didn't get any bytes. 401f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // If we have another proxy to try, try that. 402f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // 403f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // TODO(garnold) in fact there are two separate cases here: one case is an 404f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // other-than-success return code (including no return code) and no 405f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // received bytes, which is necessary due to the way callbacks are 406f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // currently processing error conditions; the second is an explicit HTTP 407f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // error code, where some data may have been received (as in the case of a 408f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // semi-successful multi-chunk fetch). This is a confusing behavior and 409f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // should be unified into a complete, coherent interface. 410f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(INFO) << "Transfer resulted in an error (" << http_response_code_ 411f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo << "), " << bytes_downloaded_ << " bytes downloaded"; 412f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo 413f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo PopProxy(); // Delete the proxy we just gave up on. 414f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo 415f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (HasProxy()) { 416f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // We have another proxy. Retry immediately. 417f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(INFO) << "Retrying with next proxy setting"; 418f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo MessageLoop::current()->PostTask( 41960ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo FROM_HERE, 42060ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback, 421f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo base::Unretained(this))); 422f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } else { 423f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // Out of proxies. Give up. 424f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(INFO) << "No further proxies, indicating transfer complete"; 425f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (delegate_) 426f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo delegate_->TransferComplete(this, false); // signal fail 427a092955cdf763260563a774f6a68e1bfb38c5a8bDarin Petkov } 428f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } else if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) { 429f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (!ignore_failure_) 4309bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes retry_count_++; 431f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(INFO) << "Transfer interrupted after downloading " 432f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo << bytes_downloaded_ << " of " << transfer_size_ << " bytes. " 433f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo << transfer_size_ - bytes_downloaded_ << " bytes remaining " 434f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo << "after " << retry_count_ << " attempt(s)"; 435f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo 436f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (retry_count_ > max_retry_count_) { 437f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(INFO) << "Reached max attempts (" << retry_count_ << ")"; 438f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (delegate_) 439f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo delegate_->TransferComplete(this, false); // signal fail 440c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com } else { 441f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // Need to restart transfer 442f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(INFO) << "Restarting transfer to download the remaining bytes"; 443f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo MessageLoop::current()->PostDelayedTask( 444f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo FROM_HERE, 445f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback, 446f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo base::Unretained(this)), 447f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo TimeDelta::FromSeconds(retry_seconds_)); 448c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com } 44949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } else { 450f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(INFO) << "Transfer completed (" << http_response_code_ 451f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo << "), " << bytes_downloaded_ << " bytes downloaded"; 452f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (delegate_) { 453f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo bool success = IsHttpResponseSuccess(); 454f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo delegate_->TransferComplete(this, success); 455f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 45649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 457f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo ignore_failure_ = false; 45849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} 45949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 46049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.comsize_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) { 46148085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold // Update HTTP response first. 46248085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold GetHttpResponseCode(); 46348085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold const size_t payload_size = size * nmemb; 46448085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold 46548085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold // Do nothing if no payload or HTTP response is an error. 4669bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnold if (payload_size == 0 || !IsHttpResponseSuccess()) { 46748085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold LOG(INFO) << "HTTP response unsuccessful (" << http_response_code_ 46848085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold << ") or no payload (" << payload_size << "), nothing to do"; 4694516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes return 0; 47048085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold } 47148085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold 4724516810fe41a39c0c55d2095679898787259ae38Andrew de los Reyes sent_byte_ = true; 473c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com { 474c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com double transfer_size_double; 475c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_easy_getinfo(curl_handle_, 476c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CURLINFO_CONTENT_LENGTH_DOWNLOAD, 477c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com &transfer_size_double), CURLE_OK); 478c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com off_t new_transfer_size = static_cast<off_t>(transfer_size_double); 479c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com if (new_transfer_size > 0) { 480c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com transfer_size_ = resume_offset_ + new_transfer_size; 481c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com } 482c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com } 48348085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold bytes_downloaded_ += payload_size; 4843fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyes in_write_callback_ = true; 48549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com if (delegate_) 486f68bbbc952aa9a71898e4939b5f36187fa564a50Alex Vakulenko delegate_->ReceivedBytes(this, ptr, payload_size); 4873fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyes in_write_callback_ = false; 48848085ba58516e94f045d3ab7e26c8f36e6a6936fGilad Arnold return payload_size; 48949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} 49049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 49149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.comvoid LibcurlHttpFetcher::Pause() { 492f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (transfer_paused_) { 493f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(ERROR) << "Fetcher already paused."; 494f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo return; 495f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 496f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo transfer_paused_ = true; 497f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (!transfer_in_progress_) { 498f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // If pause before we started a connection, we don't need to notify curl 499f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // about that, we will simply not start the connection later. 500f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo return; 501f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 50249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CHECK(curl_handle_); 503c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_ALL), CURLE_OK); 50449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} 50549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 50649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.comvoid LibcurlHttpFetcher::Unpause() { 507f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (!transfer_paused_) { 508f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo LOG(ERROR) << "Resume attempted when fetcher not paused."; 509f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo return; 510f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 511f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo transfer_paused_ = false; 512f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (restart_transfer_on_unpause_) { 513f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo restart_transfer_on_unpause_ = false; 514f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo ResumeTransfer(url_); 515f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo CurlPerformOnce(); 516f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo return; 517f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 518f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (!transfer_in_progress_) { 519f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // If resumed before starting the connection, there's no need to notify 520f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // anybody. We will simply start the connection once it is time. 521f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo return; 522f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 52349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CHECK(curl_handle_); 524c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_CONT), CURLE_OK); 525f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // Since the transfer is in progress, we need to dispatch a CurlPerformOnce() 526f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // now to let the connection continue, otherwise it would be called by the 527f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo // TimeoutCallback but with a delay. 528f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo CurlPerformOnce(); 52949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} 53049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 53129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo// This method sets up callbacks with the MessageLoop. 53229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymovoid LibcurlHttpFetcher::SetupMessageLoopSources() { 53349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com fd_set fd_read; 53449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com fd_set fd_write; 53560e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov fd_set fd_exc; 53649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 53749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com FD_ZERO(&fd_read); 53849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com FD_ZERO(&fd_write); 53960e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov FD_ZERO(&fd_exc); 54049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 54149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com int fd_max = 0; 54249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 54349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Ask libcurl for the set of file descriptors we should track on its 54449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // behalf. 545c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_multi_fdset(curl_multi_handle_, &fd_read, &fd_write, 54660e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov &fd_exc, &fd_max), CURLM_OK); 54749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 54849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // We should iterate through all file descriptors up to libcurl's fd_max or 54960e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov // the highest one we're tracking, whichever is larger. 55029b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo for (size_t t = 0; t < arraysize(fd_task_maps_); ++t) { 55129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo if (!fd_task_maps_[t].empty()) 55229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo fd_max = max(fd_max, fd_task_maps_[t].rbegin()->first); 55360e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov } 55460e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov 55560e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov // For each fd, if we're not tracking it, track it. If we are tracking it, but 55660e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov // libcurl doesn't care about it anymore, stop tracking it. After this loop, 55729b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo // there should be exactly as many tasks scheduled in fd_task_maps_[0|1] as 55860e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov // there are read/write fds that we're tracking. 55960e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov for (int fd = 0; fd <= fd_max; ++fd) { 56060e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov // Note that fd_exc is unused in the current version of libcurl so is_exc 56160e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov // should always be false. 56260e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov bool is_exc = FD_ISSET(fd, &fd_exc) != 0; 56360e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov bool must_track[2] = { 56460e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov is_exc || (FD_ISSET(fd, &fd_read) != 0), // track 0 -- read 56560e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov is_exc || (FD_ISSET(fd, &fd_write) != 0) // track 1 -- write 56660e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov }; 56729b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo MessageLoop::WatchMode watch_modes[2] = { 56829b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo MessageLoop::WatchMode::kWatchRead, 56929b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo MessageLoop::WatchMode::kWatchWrite, 57029b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo }; 57160e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov 57229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo for (size_t t = 0; t < arraysize(fd_task_maps_); ++t) { 57329b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo auto fd_task_it = fd_task_maps_[t].find(fd); 57429b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo bool tracked = fd_task_it != fd_task_maps_[t].end(); 57560e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov 57660e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov if (!must_track[t]) { 57760e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov // If we have an outstanding io_channel, remove it. 57860e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov if (tracked) { 57929b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo MessageLoop::current()->CancelTask(fd_task_it->second); 58029b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo fd_task_maps_[t].erase(fd_task_it); 58160e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov } 58260e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov continue; 58360e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov } 58460e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov 58560e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov // If we are already tracking this fd, continue -- nothing to do. 58660e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov if (tracked) 58760e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov continue; 58860e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov 58960e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov // Track a new fd. 59029b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo fd_task_maps_[t][fd] = MessageLoop::current()->WatchFileDescriptor( 59129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo FROM_HERE, 59229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo fd, 59329b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo watch_modes[t], 59429b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo true, // persistent 59529b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo base::Bind(&LibcurlHttpFetcher::CurlPerformOnce, 59629b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo base::Unretained(this))); 59760e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov 59860e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov static int io_counter = 0; 59960e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov io_counter++; 60060e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov if (io_counter % 50 == 0) { 60160e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov LOG(INFO) << "io_counter = " << io_counter; 60249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 6033270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes } 60449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 60549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 606b83371f6d7fc12a66d33eac614c0fae3aa0978baDarin Petkov // Set up a timeout callback for libcurl. 60760ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo if (timeout_id_ == MessageLoop::kTaskIdNull) { 608f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo VLOG(1) << "Setting up timeout source: " << idle_seconds_ << " seconds."; 60960ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo timeout_id_ = MessageLoop::current()->PostDelayedTask( 61060ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo FROM_HERE, 61160ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo base::Bind(&LibcurlHttpFetcher::TimeoutCallback, 61260ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo base::Unretained(this)), 61360ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo TimeDelta::FromSeconds(idle_seconds_)); 61449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 61549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} 61649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 61760ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymovoid LibcurlHttpFetcher::RetryTimeoutCallback() { 618f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo if (transfer_paused_) { 619f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo restart_transfer_on_unpause_ = true; 620f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo return; 621f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo } 6229bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes ResumeTransfer(url_); 6239bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes CurlPerformOnce(); 6249bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes} 6259bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes 62660ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymovoid LibcurlHttpFetcher::TimeoutCallback() { 62760ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo // We always re-schedule the callback, even if we don't want to be called 62860ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo // anymore. We will remove the event source separately if we don't want to 629cb319330c529b0394f6efb416dbe7b03bf38b19bAndrew de los Reyes // be called back. 63060ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo timeout_id_ = MessageLoop::current()->PostDelayedTask( 63160ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo FROM_HERE, 63260ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo base::Bind(&LibcurlHttpFetcher::TimeoutCallback, base::Unretained(this)), 63360ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo TimeDelta::FromSeconds(idle_seconds_)); 634f123ae2065ef19c172ae67a4c11cf23f1b787204Alex Deymo 635f123ae2065ef19c172ae67a4c11cf23f1b787204Alex Deymo // CurlPerformOnce() may call CleanUp(), so we need to schedule our callback 636f123ae2065ef19c172ae67a4c11cf23f1b787204Alex Deymo // first, since it could be canceled by this call. 637f123ae2065ef19c172ae67a4c11cf23f1b787204Alex Deymo if (transfer_in_progress_) 638f123ae2065ef19c172ae67a4c11cf23f1b787204Alex Deymo CurlPerformOnce(); 63949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} 64049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 64149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.comvoid LibcurlHttpFetcher::CleanUp() { 64260ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo MessageLoop::current()->CancelTask(timeout_id_); 64360ca1a7bca7cc804ec80b510483081ef894de4cdAlex Deymo timeout_id_ = MessageLoop::kTaskIdNull; 64449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 64529b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo for (size_t t = 0; t < arraysize(fd_task_maps_); ++t) { 64629b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo for (const auto& fd_taks_pair : fd_task_maps_[t]) { 64729b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo if (!MessageLoop::current()->CancelTask(fd_taks_pair.second)) { 64829b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo LOG(WARNING) << "Error canceling the watch task " 64929b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo << fd_taks_pair.second << " for " 65029b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo << (t ? "writing" : "reading") << " the fd " 65129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo << fd_taks_pair.first; 65229b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo } 65360e1415b31b58bc17017d29c8e06f6e5452fdf4eDarin Petkov } 65429b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo fd_task_maps_[t].clear(); 65549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 65649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 6579dd1e7c6bbc605c2150800f763c596ff0a4ad1c1Gilad Arnold if (curl_http_headers_) { 6589dd1e7c6bbc605c2150800f763c596ff0a4ad1c1Gilad Arnold curl_slist_free_all(curl_http_headers_); 65988b591f24cb3f94f982d7024c2e8ed25c2cc26a2Alex Vakulenko curl_http_headers_ = nullptr; 6609dd1e7c6bbc605c2150800f763c596ff0a4ad1c1Gilad Arnold } 66149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com if (curl_handle_) { 66249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com if (curl_multi_handle_) { 663c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_multi_remove_handle(curl_multi_handle_, curl_handle_), 664c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CURLM_OK); 66549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 66649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com curl_easy_cleanup(curl_handle_); 66788b591f24cb3f94f982d7024c2e8ed25c2cc26a2Alex Vakulenko curl_handle_ = nullptr; 66849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 66949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com if (curl_multi_handle_) { 670c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com CHECK_EQ(curl_multi_cleanup(curl_multi_handle_), CURLM_OK); 67188b591f24cb3f94f982d7024c2e8ed25c2cc26a2Alex Vakulenko curl_multi_handle_ = nullptr; 67249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 67349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com transfer_in_progress_ = false; 674f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo transfer_paused_ = false; 675f28585764e91b7c25a7c2856ff645c8bb22d64a9Alex Deymo restart_transfer_on_unpause_ = false; 67649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} 67749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 6783fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyesvoid LibcurlHttpFetcher::GetHttpResponseCode() { 679d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko long http_response_code = 0; // NOLINT(runtime/int) - curl needs long. 68056ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo if (base::StartsWith(url_, "file://", base::CompareCase::INSENSITIVE_ASCII)) { 68156ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo // Fake out a valid response code for file:// URLs. 68256ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo http_response_code_ = 299; 68356ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo } else if (curl_easy_getinfo(curl_handle_, 68456ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo CURLINFO_RESPONSE_CODE, 68556ccb072b55a48099c634a9dfb24e3af2b6213caAlex Deymo &http_response_code) == CURLE_OK) { 6863fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyes http_response_code_ = static_cast<int>(http_response_code); 6873fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyes } 6883fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyes} 6893fd5d30433509859bfdcc0b650e242981410c6a7Andrew de los Reyes 69049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} // namespace chromeos_update_engine 691