| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium OS Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "update_engine/libcurl_http_fetcher.h" | 5 #include "update_engine/libcurl_http_fetcher.h" |
| 6 #include <algorithm> | 6 #include <algorithm> |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 | 8 |
| 9 using std::max; | 9 using std::max; |
| 10 using std::make_pair; | 10 using std::make_pair; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_CAPATH, kCACertificatesPath), | 74 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_CAPATH, kCACertificatesPath), |
| 75 CURLE_OK); | 75 CURLE_OK); |
| 76 | 76 |
| 77 CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK); | 77 CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK); |
| 78 transfer_in_progress_ = true; | 78 transfer_in_progress_ = true; |
| 79 } | 79 } |
| 80 | 80 |
| 81 // Begins the transfer, which must not have already been started. | 81 // Begins the transfer, which must not have already been started. |
| 82 void LibcurlHttpFetcher::BeginTransfer(const std::string& url) { | 82 void LibcurlHttpFetcher::BeginTransfer(const std::string& url) { |
| 83 transfer_size_ = -1; | 83 transfer_size_ = -1; |
| 84 bytes_downloaded_ = 0; | |
| 85 resume_offset_ = 0; | 84 resume_offset_ = 0; |
| 86 retry_count_ = 0; | 85 retry_count_ = 0; |
| 87 http_response_code_ = 0; | 86 http_response_code_ = 0; |
| 88 ResumeTransfer(url); | 87 ResumeTransfer(url); |
| 89 CurlPerformOnce(); | 88 CurlPerformOnce(); |
| 90 } | 89 } |
| 91 | 90 |
| 92 void LibcurlHttpFetcher::TerminateTransfer() { | 91 void LibcurlHttpFetcher::TerminateTransfer() { |
| 93 CleanUp(); | 92 if (in_write_callback_) |
| 93 terminate_requested_ = true; |
| 94 else |
| 95 CleanUp(); |
| 94 } | 96 } |
| 95 | 97 |
| 96 void LibcurlHttpFetcher::CurlPerformOnce() { | 98 void LibcurlHttpFetcher::CurlPerformOnce() { |
| 97 CHECK(transfer_in_progress_); | 99 CHECK(transfer_in_progress_); |
| 98 int running_handles = 0; | 100 int running_handles = 0; |
| 99 CURLMcode retcode = CURLM_CALL_MULTI_PERFORM; | 101 CURLMcode retcode = CURLM_CALL_MULTI_PERFORM; |
| 100 | 102 |
| 101 // libcurl may request that we immediately call curl_multi_perform after it | 103 // libcurl may request that we immediately call curl_multi_perform after it |
| 102 // returns, so we do. libcurl promises that curl_multi_perform will not block. | 104 // returns, so we do. libcurl promises that curl_multi_perform will not block. |
| 103 while (CURLM_CALL_MULTI_PERFORM == retcode) { | 105 while (CURLM_CALL_MULTI_PERFORM == retcode) { |
| 104 retcode = curl_multi_perform(curl_multi_handle_, &running_handles); | 106 retcode = curl_multi_perform(curl_multi_handle_, &running_handles); |
| 107 if (terminate_requested_) { |
| 108 CleanUp(); |
| 109 return; |
| 110 } |
| 105 } | 111 } |
| 106 if (0 == running_handles) { | 112 if (0 == running_handles) { |
| 107 long http_response_code = 0; | 113 GetHttpResponseCode(); |
| 108 if (curl_easy_getinfo(curl_handle_, | 114 if (http_response_code_) { |
| 109 CURLINFO_RESPONSE_CODE, | 115 LOG(INFO) << "HTTP response code: " << http_response_code_; |
| 110 &http_response_code) == CURLE_OK) { | |
| 111 LOG(INFO) << "HTTP response code: " << http_response_code; | |
| 112 } else { | 116 } else { |
| 113 LOG(ERROR) << "Unable to get http response code."; | 117 LOG(ERROR) << "Unable to get http response code."; |
| 114 } | 118 } |
| 115 http_response_code_ = static_cast<int>(http_response_code); | |
| 116 | 119 |
| 117 // we're done! | 120 // we're done! |
| 118 CleanUp(); | 121 CleanUp(); |
| 119 | 122 |
| 120 if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) { | 123 if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) { |
| 121 // Need to restart transfer | 124 // Need to restart transfer |
| 122 retry_count_++; | 125 retry_count_++; |
| 123 LOG(INFO) << "Restarting transfer b/c we finished, had downloaded " | 126 LOG(INFO) << "Restarting transfer b/c we finished, had downloaded " |
| 124 << bytes_downloaded_ << " bytes, but transfer_size_ is " | 127 << bytes_downloaded_ << " bytes, but transfer_size_ is " |
| 125 << transfer_size_ << ". retry_count: " << retry_count_; | 128 << transfer_size_ << ". retry_count: " << retry_count_; |
| 126 if (retry_count_ > kMaxRetriesCount) { | 129 if (retry_count_ > kMaxRetriesCount) { |
| 127 if (delegate_) | 130 if (delegate_) |
| 128 delegate_->TransferComplete(this, false); // success | 131 delegate_->TransferComplete(this, false); // success |
| 129 } else { | 132 } else { |
| 130 g_timeout_add_seconds(retry_seconds_, | 133 g_timeout_add_seconds(retry_seconds_, |
| 131 &LibcurlHttpFetcher::StaticRetryTimeoutCallback, | 134 &LibcurlHttpFetcher::StaticRetryTimeoutCallback, |
| 132 this); | 135 this); |
| 133 } | 136 } |
| 134 return; | 137 return; |
| 135 } else { | 138 } else { |
| 136 if (delegate_) { | 139 if (delegate_) { |
| 137 // success is when http_response_code is 2xx | 140 // success is when http_response_code is 2xx |
| 138 bool success = (http_response_code >= 200) && | 141 bool success = (http_response_code_ >= 200) && |
| 139 (http_response_code < 300); | 142 (http_response_code_ < 300); |
| 140 delegate_->TransferComplete(this, success); | 143 delegate_->TransferComplete(this, success); |
| 141 } | 144 } |
| 142 } | 145 } |
| 143 } else { | 146 } else { |
| 144 // set up callback | 147 // set up callback |
| 145 SetupMainloopSources(); | 148 SetupMainloopSources(); |
| 146 } | 149 } |
| 147 } | 150 } |
| 148 | 151 |
| 149 size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) { | 152 size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) { |
| 153 GetHttpResponseCode(); |
| 150 { | 154 { |
| 151 double transfer_size_double; | 155 double transfer_size_double; |
| 152 CHECK_EQ(curl_easy_getinfo(curl_handle_, | 156 CHECK_EQ(curl_easy_getinfo(curl_handle_, |
| 153 CURLINFO_CONTENT_LENGTH_DOWNLOAD, | 157 CURLINFO_CONTENT_LENGTH_DOWNLOAD, |
| 154 &transfer_size_double), CURLE_OK); | 158 &transfer_size_double), CURLE_OK); |
| 155 off_t new_transfer_size = static_cast<off_t>(transfer_size_double); | 159 off_t new_transfer_size = static_cast<off_t>(transfer_size_double); |
| 156 if (new_transfer_size > 0) { | 160 if (new_transfer_size > 0) { |
| 157 transfer_size_ = resume_offset_ + new_transfer_size; | 161 transfer_size_ = resume_offset_ + new_transfer_size; |
| 158 } | 162 } |
| 159 } | 163 } |
| 160 bytes_downloaded_ += size * nmemb; | 164 bytes_downloaded_ += size * nmemb; |
| 165 in_write_callback_ = true; |
| 161 if (delegate_) | 166 if (delegate_) |
| 162 delegate_->ReceivedBytes(this, reinterpret_cast<char*>(ptr), size * nmemb); | 167 delegate_->ReceivedBytes(this, reinterpret_cast<char*>(ptr), size * nmemb); |
| 168 in_write_callback_ = false; |
| 163 return size * nmemb; | 169 return size * nmemb; |
| 164 } | 170 } |
| 165 | 171 |
| 166 void LibcurlHttpFetcher::Pause() { | 172 void LibcurlHttpFetcher::Pause() { |
| 167 CHECK(curl_handle_); | 173 CHECK(curl_handle_); |
| 168 CHECK(transfer_in_progress_); | 174 CHECK(transfer_in_progress_); |
| 169 CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_ALL), CURLE_OK); | 175 CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_ALL), CURLE_OK); |
| 170 } | 176 } |
| 171 | 177 |
| 172 void LibcurlHttpFetcher::Unpause() { | 178 void LibcurlHttpFetcher::Unpause() { |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 287 curl_easy_cleanup(curl_handle_); | 293 curl_easy_cleanup(curl_handle_); |
| 288 curl_handle_ = NULL; | 294 curl_handle_ = NULL; |
| 289 } | 295 } |
| 290 if (curl_multi_handle_) { | 296 if (curl_multi_handle_) { |
| 291 CHECK_EQ(curl_multi_cleanup(curl_multi_handle_), CURLM_OK); | 297 CHECK_EQ(curl_multi_cleanup(curl_multi_handle_), CURLM_OK); |
| 292 curl_multi_handle_ = NULL; | 298 curl_multi_handle_ = NULL; |
| 293 } | 299 } |
| 294 transfer_in_progress_ = false; | 300 transfer_in_progress_ = false; |
| 295 } | 301 } |
| 296 | 302 |
| 303 void LibcurlHttpFetcher::GetHttpResponseCode() { |
| 304 long http_response_code = 0; |
| 305 if (curl_easy_getinfo(curl_handle_, |
| 306 CURLINFO_RESPONSE_CODE, |
| 307 &http_response_code) == CURLE_OK) { |
| 308 http_response_code_ = static_cast<int>(http_response_code); |
| 309 } |
| 310 } |
| 311 |
| 297 } // namespace chromeos_update_engine | 312 } // namespace chromeos_update_engine |
| OLD | NEW |