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 // NOTE: lifted from src/platform/update_engine and tweaked for cashew | 5 // NOTE: lifted from src/platform/update_engine and tweaked for cashew |
6 // TODO(vlaviano): see http_fetcher.h | 6 // TODO(vlaviano): see http_fetcher.h |
7 | 7 |
8 #include "src/libcurl_http_fetcher.h" | 8 #include "src/libcurl_http_fetcher.h" |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 | 11 |
12 #include <glog/logging.h> // NOLINT | 12 #include <glog/logging.h> // NOLINT |
13 | 13 |
14 using std::max; | 14 using std::max; |
15 using std::make_pair; | 15 using std::make_pair; |
16 | 16 |
17 // This is a concrete implementation of HttpFetcher that uses libcurl to do the | 17 // This is a concrete implementation of HttpFetcher that uses libcurl to do the |
18 // http work. | 18 // http work. |
19 | 19 |
20 namespace cashew { | 20 namespace cashew { |
21 | 21 |
22 namespace { | 22 namespace { |
23 const int kMaxRetriesCount = 20; | 23 const int kMaxRetriesCount = 20; |
24 const char kCACertificatesPath[] = "/usr/share/cashew/ca-certificates"; | |
25 } | 24 } |
26 | 25 |
27 LibcurlHttpFetcher::~LibcurlHttpFetcher() { | 26 LibcurlHttpFetcher::~LibcurlHttpFetcher() { |
28 CleanUp(); | 27 CleanUp(); |
29 } | 28 } |
30 | 29 |
31 void LibcurlHttpFetcher::ResumeTransfer(const std::string& url) { | 30 void LibcurlHttpFetcher::ResumeTransfer(const std::string& url) { |
32 LOG(INFO) << "Starting/Resuming transfer"; | 31 LOG(INFO) << "Starting/Resuming transfer"; |
33 CHECK(!transfer_in_progress_); | 32 CHECK(!transfer_in_progress_); |
34 url_ = url; | 33 url_ = url; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 CURLE_OK); | 65 CURLE_OK); |
67 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_LOW_SPEED_TIME, 3 * 60), | 66 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_LOW_SPEED_TIME, 3 * 60), |
68 CURLE_OK); | 67 CURLE_OK); |
69 | 68 |
70 // By default, libcurl doesn't follow redirections. Allow up to | 69 // By default, libcurl doesn't follow redirections. Allow up to |
71 // |kMaxRedirects| redirections. | 70 // |kMaxRedirects| redirections. |
72 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_FOLLOWLOCATION, 1), CURLE_OK); | 71 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_FOLLOWLOCATION, 1), CURLE_OK); |
73 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_MAXREDIRS, kMaxRedirects), | 72 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_MAXREDIRS, kMaxRedirects), |
74 CURLE_OK); | 73 CURLE_OK); |
75 | 74 |
76 // Makes sure that peer certificate verification is enabled and restricts the | 75 // Makes sure that peer certificate verification is enabled |
77 // set of trusted certificates. | |
78 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_SSL_VERIFYPEER, 1), CURLE_OK); | 76 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_SSL_VERIFYPEER, 1), CURLE_OK); |
79 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_CAPATH, kCACertificatesPath), | |
80 CURLE_OK); | |
81 | 77 |
82 CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK); | 78 CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK); |
83 transfer_in_progress_ = true; | 79 transfer_in_progress_ = true; |
84 } | 80 } |
85 | 81 |
86 // Begins the transfer, which must not have already been started. | 82 // Begins the transfer, which must not have already been started. |
87 void LibcurlHttpFetcher::BeginTransfer(const std::string& url) { | 83 void LibcurlHttpFetcher::BeginTransfer(const std::string& url) { |
88 DLOG(INFO) << "BeginTransfer"; | 84 DLOG(INFO) << "BeginTransfer"; |
89 transfer_size_ = -1; | 85 transfer_size_ = -1; |
90 bytes_downloaded_ = 0; | 86 bytes_downloaded_ = 0; |
(...skipping 13 matching lines...) Expand all Loading... |
104 CHECK(transfer_in_progress_); | 100 CHECK(transfer_in_progress_); |
105 int running_handles = 0; | 101 int running_handles = 0; |
106 CURLMcode retcode = CURLM_CALL_MULTI_PERFORM; | 102 CURLMcode retcode = CURLM_CALL_MULTI_PERFORM; |
107 | 103 |
108 // libcurl may request that we immediately call curl_multi_perform after it | 104 // libcurl may request that we immediately call curl_multi_perform after it |
109 // returns, so we do. libcurl promises that curl_multi_perform will not block. | 105 // returns, so we do. libcurl promises that curl_multi_perform will not block. |
110 while (CURLM_CALL_MULTI_PERFORM == retcode) { | 106 while (CURLM_CALL_MULTI_PERFORM == retcode) { |
111 retcode = curl_multi_perform(curl_multi_handle_, &running_handles); | 107 retcode = curl_multi_perform(curl_multi_handle_, &running_handles); |
112 } | 108 } |
113 if (0 == running_handles) { | 109 if (0 == running_handles) { |
114 long http_response_code = 0; // NOLINT | 110 GetHttpResponseCode(); |
115 if (curl_easy_getinfo(curl_handle_, | 111 if (http_response_code_) { |
116 CURLINFO_RESPONSE_CODE, | 112 LOG(INFO) << "HTTP response code: " << http_response_code_; |
117 &http_response_code) == CURLE_OK) { | |
118 LOG(INFO) << "HTTP response code: " << http_response_code; | |
119 } else { | 113 } else { |
120 LOG(ERROR) << "Unable to get http response code."; | 114 LOG(WARNING) << "Unable to get http response code."; |
121 } | 115 } |
122 http_response_code_ = static_cast<int>(http_response_code); | |
123 | 116 |
124 // we're done! | 117 // we're done! |
125 CleanUp(); | 118 CleanUp(); |
126 | 119 |
127 if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) { | 120 if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) { |
128 // Need to restart transfer | 121 // Need to restart transfer |
129 retry_count_++; | 122 retry_count_++; |
130 LOG(INFO) << "Restarting transfer b/c we finished, had downloaded " | 123 LOG(INFO) << "Restarting transfer b/c we finished, had downloaded " |
131 << bytes_downloaded_ << " bytes, but transfer_size_ is " | 124 << bytes_downloaded_ << " bytes, but transfer_size_ is " |
132 << transfer_size_ << ". retry_count: " << retry_count_; | 125 << transfer_size_ << ". retry_count: " << retry_count_; |
133 if (retry_count_ > kMaxRetriesCount) { | 126 if (retry_count_ > kMaxRetriesCount) { |
134 if (delegate_) | 127 if (delegate_) |
135 delegate_->TransferComplete(this, false); // success | 128 delegate_->TransferComplete(this, false); // success |
136 } else { | 129 } else { |
137 g_timeout_add_seconds(retry_seconds_, | 130 g_timeout_add_seconds(retry_seconds_, |
138 &LibcurlHttpFetcher::StaticRetryTimeoutCallback, | 131 &LibcurlHttpFetcher::StaticRetryTimeoutCallback, |
139 this); | 132 this); |
140 } | 133 } |
141 return; | 134 return; |
142 } else { | 135 } else { |
143 if (delegate_) { | 136 if (delegate_) { |
144 // success is when http_response_code is 2xx | 137 // success is when http_response_code_ is 2xx |
145 bool success = (http_response_code >= 200) && | 138 bool success = (http_response_code_ >= 200) && |
146 (http_response_code < 300); | 139 (http_response_code_ < 300); |
147 delegate_->TransferComplete(this, success); | 140 delegate_->TransferComplete(this, success); |
148 } | 141 } |
149 } | 142 } |
150 } else { | 143 } else { |
151 // set up callback | 144 // set up callback |
152 SetupMainloopSources(); | 145 SetupMainloopSources(); |
153 } | 146 } |
154 } | 147 } |
155 | 148 |
156 size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) { | 149 size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) { |
| 150 GetHttpResponseCode(); |
157 DLOG(INFO) << "LibcurlWrite"; | 151 DLOG(INFO) << "LibcurlWrite"; |
158 { | 152 { |
159 double transfer_size_double; | 153 double transfer_size_double; |
160 CHECK_EQ(curl_easy_getinfo(curl_handle_, | 154 CHECK_EQ(curl_easy_getinfo(curl_handle_, |
161 CURLINFO_CONTENT_LENGTH_DOWNLOAD, | 155 CURLINFO_CONTENT_LENGTH_DOWNLOAD, |
162 &transfer_size_double), CURLE_OK); | 156 &transfer_size_double), CURLE_OK); |
163 off_t new_transfer_size = static_cast<off_t>(transfer_size_double); | 157 off_t new_transfer_size = static_cast<off_t>(transfer_size_double); |
164 if (new_transfer_size > 0) { | 158 if (new_transfer_size > 0) { |
165 transfer_size_ = resume_offset_ + new_transfer_size; | 159 transfer_size_ = resume_offset_ + new_transfer_size; |
166 } | 160 } |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 curl_easy_cleanup(curl_handle_); | 293 curl_easy_cleanup(curl_handle_); |
300 curl_handle_ = NULL; | 294 curl_handle_ = NULL; |
301 } | 295 } |
302 if (curl_multi_handle_) { | 296 if (curl_multi_handle_) { |
303 CHECK_EQ(curl_multi_cleanup(curl_multi_handle_), CURLM_OK); | 297 CHECK_EQ(curl_multi_cleanup(curl_multi_handle_), CURLM_OK); |
304 curl_multi_handle_ = NULL; | 298 curl_multi_handle_ = NULL; |
305 } | 299 } |
306 transfer_in_progress_ = false; | 300 transfer_in_progress_ = false; |
307 } | 301 } |
308 | 302 |
| 303 void LibcurlHttpFetcher::GetHttpResponseCode() { |
| 304 long http_response_code = 0; // NOLINT |
| 305 CURLcode result = curl_easy_getinfo(curl_handle_, |
| 306 CURLINFO_RESPONSE_CODE, |
| 307 &http_response_code); |
| 308 if (result == CURLE_OK) { |
| 309 http_response_code_ = static_cast<int>(http_response_code); |
| 310 } else { |
| 311 DLOG(WARNING) << "GetHttpResponseCode: curl_easy_getinfo failed: " |
| 312 << curl_easy_strerror(result); |
| 313 } |
| 314 } |
| 315 |
309 } // namespace cashew | 316 } // namespace cashew |
OLD | NEW |