| Index: src/platform/update_engine/libcurl_http_fetcher.cc
|
| diff --git a/src/platform/update_engine/libcurl_http_fetcher.cc b/src/platform/update_engine/libcurl_http_fetcher.cc
|
| index 624e6a9539db633e8b78307521c2bb04f1bd8318..9ed0c64b90341eaeb17777e24bc84293da5e4b56 100644
|
| --- a/src/platform/update_engine/libcurl_http_fetcher.cc
|
| +++ b/src/platform/update_engine/libcurl_http_fetcher.cc
|
| @@ -2,8 +2,12 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "base/logging.h"
|
| #include "update_engine/libcurl_http_fetcher.h"
|
| +#include <algorithm>
|
| +#include "chromeos/obsolete_logging.h"
|
| +
|
| +using std::max;
|
| +using std::make_pair;
|
|
|
| // This is a concrete implementation of HttpFetcher that uses libcurl to do the
|
| // http work.
|
| @@ -14,8 +18,7 @@ LibcurlHttpFetcher::~LibcurlHttpFetcher() {
|
| CleanUp();
|
| }
|
|
|
| -// Begins the transfer, which must not have already been started.
|
| -void LibcurlHttpFetcher::BeginTransfer(const std::string& url) {
|
| +void LibcurlHttpFetcher::ResumeTransfer(const std::string& url) {
|
| CHECK(!transfer_in_progress_);
|
| url_ = url;
|
| curl_multi_handle_ = curl_multi_init();
|
| @@ -25,22 +28,40 @@ void LibcurlHttpFetcher::BeginTransfer(const std::string& url) {
|
| CHECK(curl_handle_);
|
|
|
| if (post_data_set_) {
|
| - CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_POST, 1));
|
| - CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDS,
|
| - &post_data_[0]));
|
| - CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDSIZE,
|
| - post_data_.size()));
|
| + CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POST, 1), CURLE_OK);
|
| + CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDS,
|
| + &post_data_[0]),
|
| + CURLE_OK);
|
| + CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDSIZE,
|
| + post_data_.size()),
|
| + CURLE_OK);
|
| }
|
|
|
| - CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_WRITEDATA, this));
|
| - CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_WRITEFUNCTION,
|
| - StaticLibcurlWrite));
|
| - CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_URL, url_.c_str()));
|
| - CHECK_EQ(CURLM_OK, curl_multi_add_handle(curl_multi_handle_, curl_handle_));
|
| + if (bytes_downloaded_ > 0) {
|
| + // Resume from where we left off
|
| + resume_offset_ = bytes_downloaded_;
|
| + CHECK_EQ(curl_easy_setopt(curl_handle_,
|
| + CURLOPT_RESUME_FROM_LARGE,
|
| + bytes_downloaded_), CURLE_OK);
|
| + }
|
| +
|
| + CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_WRITEDATA, this), CURLE_OK);
|
| + CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_WRITEFUNCTION,
|
| + StaticLibcurlWrite), CURLE_OK);
|
| + CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_URL, url_.c_str()), CURLE_OK);
|
| + CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK);
|
| transfer_in_progress_ = true;
|
| CurlPerformOnce();
|
| }
|
|
|
| +// Begins the transfer, which must not have already been started.
|
| +void LibcurlHttpFetcher::BeginTransfer(const std::string& url) {
|
| + transfer_size_ = -1;
|
| + bytes_downloaded_ = 0;
|
| + resume_offset_ = 0;
|
| + ResumeTransfer(url);
|
| +}
|
| +
|
| void LibcurlHttpFetcher::TerminateTransfer() {
|
| CleanUp();
|
| }
|
| @@ -59,8 +80,14 @@ void LibcurlHttpFetcher::CurlPerformOnce() {
|
| if (0 == running_handles) {
|
| // we're done!
|
| CleanUp();
|
| - if (delegate_)
|
| - delegate_->TransferComplete(this, true); // success
|
| +
|
| + if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) {
|
| + ResumeTransfer(url_);
|
| + } else {
|
| + if (delegate_) {
|
| + delegate_->TransferComplete(this, true); // success
|
| + }
|
| + }
|
| } else {
|
| // set up callback
|
| SetupMainloopSources();
|
| @@ -68,6 +95,17 @@ void LibcurlHttpFetcher::CurlPerformOnce() {
|
| }
|
|
|
| size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) {
|
| + {
|
| + double transfer_size_double;
|
| + CHECK_EQ(curl_easy_getinfo(curl_handle_,
|
| + CURLINFO_CONTENT_LENGTH_DOWNLOAD,
|
| + &transfer_size_double), CURLE_OK);
|
| + off_t new_transfer_size = static_cast<off_t>(transfer_size_double);
|
| + if (new_transfer_size > 0) {
|
| + transfer_size_ = resume_offset_ + new_transfer_size;
|
| + }
|
| + }
|
| + bytes_downloaded_ += size * nmemb;
|
| if (delegate_)
|
| delegate_->ReceivedBytes(this, reinterpret_cast<char*>(ptr), size * nmemb);
|
| return size * nmemb;
|
| @@ -76,13 +114,13 @@ size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) {
|
| void LibcurlHttpFetcher::Pause() {
|
| CHECK(curl_handle_);
|
| CHECK(transfer_in_progress_);
|
| - CHECK_EQ(CURLE_OK, curl_easy_pause(curl_handle_, CURLPAUSE_ALL));
|
| + CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_ALL), CURLE_OK);
|
| }
|
|
|
| void LibcurlHttpFetcher::Unpause() {
|
| CHECK(curl_handle_);
|
| CHECK(transfer_in_progress_);
|
| - CHECK_EQ(CURLE_OK, curl_easy_pause(curl_handle_, CURLPAUSE_CONT));
|
| + CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_CONT), CURLE_OK);
|
| }
|
|
|
| // This method sets up callbacks with the glib main loop.
|
| @@ -99,8 +137,8 @@ void LibcurlHttpFetcher::SetupMainloopSources() {
|
|
|
| // Ask libcurl for the set of file descriptors we should track on its
|
| // behalf.
|
| - CHECK_EQ(CURLM_OK, curl_multi_fdset(curl_multi_handle_, &fd_read, &fd_write,
|
| - &fd_exec, &fd_max));
|
| + CHECK_EQ(curl_multi_fdset(curl_multi_handle_, &fd_read, &fd_write,
|
| + &fd_exec, &fd_max), CURLM_OK);
|
|
|
| // We should iterate through all file descriptors up to libcurl's fd_max or
|
| // the highest one we're tracking, whichever is larger
|
| @@ -113,7 +151,7 @@ void LibcurlHttpFetcher::SetupMainloopSources() {
|
| // in io_channels_ as there are fds that we're tracking.
|
| for (int i = 0; i <= fd_max; i++) {
|
| if (!(FD_ISSET(i, &fd_read) || FD_ISSET(i, &fd_write) ||
|
| - FD_ISSET(i, &fd_exec))) {
|
| + FD_ISSET(i, &fd_exec))) {
|
| // if we have an outstanding io_channel, remove it
|
| if (io_channels_.find(i) != io_channels_.end()) {
|
| g_source_remove(io_channels_[i].second);
|
| @@ -139,7 +177,7 @@ void LibcurlHttpFetcher::SetupMainloopSources() {
|
|
|
| // Wet up a timeout callback for libcurl
|
| long ms = 0;
|
| - CHECK_EQ(CURLM_OK, curl_multi_timeout(curl_multi_handle_, &ms));
|
| + CHECK_EQ(curl_multi_timeout(curl_multi_handle_, &ms), CURLM_OK);
|
| if (ms < 0) {
|
| // From http://curl.haxx.se/libcurl/c/curl_multi_timeout.html:
|
| // if libcurl returns a -1 timeout here, it just means that libcurl
|
| @@ -210,14 +248,14 @@ void LibcurlHttpFetcher::CleanUp() {
|
|
|
| if (curl_handle_) {
|
| if (curl_multi_handle_) {
|
| - CHECK_EQ(CURLM_OK,
|
| - curl_multi_remove_handle(curl_multi_handle_, curl_handle_));
|
| + CHECK_EQ(curl_multi_remove_handle(curl_multi_handle_, curl_handle_),
|
| + CURLM_OK);
|
| }
|
| curl_easy_cleanup(curl_handle_);
|
| curl_handle_ = NULL;
|
| }
|
| if (curl_multi_handle_) {
|
| - CHECK_EQ(CURLM_OK, curl_multi_cleanup(curl_multi_handle_));
|
| + CHECK_EQ(curl_multi_cleanup(curl_multi_handle_), CURLM_OK);
|
| curl_multi_handle_ = NULL;
|
| }
|
| transfer_in_progress_ = false;
|
|
|