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