Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: src/platform/update_engine/libcurl_http_fetcher.cc

Issue 466036: AU: Beginnings of delta support (Closed)
Patch Set: Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/platform/update_engine/libcurl_http_fetcher.h ('k') | src/platform/update_engine/main.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "base/logging.h"
6 #include "update_engine/libcurl_http_fetcher.h" 5 #include "update_engine/libcurl_http_fetcher.h"
6 #include <algorithm>
7 #include "chromeos/obsolete_logging.h"
8
9 using std::max;
10 using std::make_pair;
7 11
8 // This is a concrete implementation of HttpFetcher that uses libcurl to do the 12 // This is a concrete implementation of HttpFetcher that uses libcurl to do the
9 // http work. 13 // http work.
10 14
11 namespace chromeos_update_engine { 15 namespace chromeos_update_engine {
12 16
13 LibcurlHttpFetcher::~LibcurlHttpFetcher() { 17 LibcurlHttpFetcher::~LibcurlHttpFetcher() {
14 CleanUp(); 18 CleanUp();
15 } 19 }
16 20
17 // Begins the transfer, which must not have already been started. 21 void LibcurlHttpFetcher::ResumeTransfer(const std::string& url) {
18 void LibcurlHttpFetcher::BeginTransfer(const std::string& url) {
19 CHECK(!transfer_in_progress_); 22 CHECK(!transfer_in_progress_);
20 url_ = url; 23 url_ = url;
21 curl_multi_handle_ = curl_multi_init(); 24 curl_multi_handle_ = curl_multi_init();
22 CHECK(curl_multi_handle_); 25 CHECK(curl_multi_handle_);
23 26
24 curl_handle_ = curl_easy_init(); 27 curl_handle_ = curl_easy_init();
25 CHECK(curl_handle_); 28 CHECK(curl_handle_);
26 29
27 if (post_data_set_) { 30 if (post_data_set_) {
28 CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_POST, 1)); 31 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POST, 1), CURLE_OK);
29 CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDS, 32 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDS,
30 &post_data_[0])); 33 &post_data_[0]),
31 CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDSIZE, 34 CURLE_OK);
32 post_data_.size())); 35 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDSIZE,
36 post_data_.size()),
37 CURLE_OK);
33 } 38 }
34 39
35 CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_WRITEDATA, this)); 40 if (bytes_downloaded_ > 0) {
36 CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_WRITEFUNCTION, 41 // Resume from where we left off
37 StaticLibcurlWrite)); 42 resume_offset_ = bytes_downloaded_;
38 CHECK_EQ(CURLE_OK, curl_easy_setopt(curl_handle_, CURLOPT_URL, url_.c_str())); 43 CHECK_EQ(curl_easy_setopt(curl_handle_,
39 CHECK_EQ(CURLM_OK, curl_multi_add_handle(curl_multi_handle_, curl_handle_)); 44 CURLOPT_RESUME_FROM_LARGE,
45 bytes_downloaded_), CURLE_OK);
46 }
47
48 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_WRITEDATA, this), CURLE_OK);
49 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_WRITEFUNCTION,
50 StaticLibcurlWrite), CURLE_OK);
51 CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_URL, url_.c_str()), CURLE_OK);
52 CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK);
40 transfer_in_progress_ = true; 53 transfer_in_progress_ = true;
41 CurlPerformOnce(); 54 CurlPerformOnce();
42 } 55 }
43 56
57 // Begins the transfer, which must not have already been started.
58 void LibcurlHttpFetcher::BeginTransfer(const std::string& url) {
59 transfer_size_ = -1;
60 bytes_downloaded_ = 0;
61 resume_offset_ = 0;
62 ResumeTransfer(url);
63 }
64
44 void LibcurlHttpFetcher::TerminateTransfer() { 65 void LibcurlHttpFetcher::TerminateTransfer() {
45 CleanUp(); 66 CleanUp();
46 } 67 }
47 68
48 // TODO(adlr): detect network failures 69 // TODO(adlr): detect network failures
49 void LibcurlHttpFetcher::CurlPerformOnce() { 70 void LibcurlHttpFetcher::CurlPerformOnce() {
50 CHECK(transfer_in_progress_); 71 CHECK(transfer_in_progress_);
51 int running_handles = 0; 72 int running_handles = 0;
52 CURLMcode retcode = CURLM_CALL_MULTI_PERFORM; 73 CURLMcode retcode = CURLM_CALL_MULTI_PERFORM;
53 74
54 // libcurl may request that we immediately call curl_multi_perform after it 75 // libcurl may request that we immediately call curl_multi_perform after it
55 // returns, so we do. libcurl promises that curl_multi_perform will not block. 76 // returns, so we do. libcurl promises that curl_multi_perform will not block.
56 while (CURLM_CALL_MULTI_PERFORM == retcode) { 77 while (CURLM_CALL_MULTI_PERFORM == retcode) {
57 retcode = curl_multi_perform(curl_multi_handle_, &running_handles); 78 retcode = curl_multi_perform(curl_multi_handle_, &running_handles);
58 } 79 }
59 if (0 == running_handles) { 80 if (0 == running_handles) {
60 // we're done! 81 // we're done!
61 CleanUp(); 82 CleanUp();
62 if (delegate_) 83
63 delegate_->TransferComplete(this, true); // success 84 if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) {
85 ResumeTransfer(url_);
86 } else {
87 if (delegate_) {
88 delegate_->TransferComplete(this, true); // success
89 }
90 }
64 } else { 91 } else {
65 // set up callback 92 // set up callback
66 SetupMainloopSources(); 93 SetupMainloopSources();
67 } 94 }
68 } 95 }
69 96
70 size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) { 97 size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) {
98 {
99 double transfer_size_double;
100 CHECK_EQ(curl_easy_getinfo(curl_handle_,
101 CURLINFO_CONTENT_LENGTH_DOWNLOAD,
102 &transfer_size_double), CURLE_OK);
103 off_t new_transfer_size = static_cast<off_t>(transfer_size_double);
104 if (new_transfer_size > 0) {
105 transfer_size_ = resume_offset_ + new_transfer_size;
106 }
107 }
108 bytes_downloaded_ += size * nmemb;
71 if (delegate_) 109 if (delegate_)
72 delegate_->ReceivedBytes(this, reinterpret_cast<char*>(ptr), size * nmemb); 110 delegate_->ReceivedBytes(this, reinterpret_cast<char*>(ptr), size * nmemb);
73 return size * nmemb; 111 return size * nmemb;
74 } 112 }
75 113
76 void LibcurlHttpFetcher::Pause() { 114 void LibcurlHttpFetcher::Pause() {
77 CHECK(curl_handle_); 115 CHECK(curl_handle_);
78 CHECK(transfer_in_progress_); 116 CHECK(transfer_in_progress_);
79 CHECK_EQ(CURLE_OK, curl_easy_pause(curl_handle_, CURLPAUSE_ALL)); 117 CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_ALL), CURLE_OK);
80 } 118 }
81 119
82 void LibcurlHttpFetcher::Unpause() { 120 void LibcurlHttpFetcher::Unpause() {
83 CHECK(curl_handle_); 121 CHECK(curl_handle_);
84 CHECK(transfer_in_progress_); 122 CHECK(transfer_in_progress_);
85 CHECK_EQ(CURLE_OK, curl_easy_pause(curl_handle_, CURLPAUSE_CONT)); 123 CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_CONT), CURLE_OK);
86 } 124 }
87 125
88 // This method sets up callbacks with the glib main loop. 126 // This method sets up callbacks with the glib main loop.
89 void LibcurlHttpFetcher::SetupMainloopSources() { 127 void LibcurlHttpFetcher::SetupMainloopSources() {
90 fd_set fd_read; 128 fd_set fd_read;
91 fd_set fd_write; 129 fd_set fd_write;
92 fd_set fd_exec; 130 fd_set fd_exec;
93 131
94 FD_ZERO(&fd_read); 132 FD_ZERO(&fd_read);
95 FD_ZERO(&fd_write); 133 FD_ZERO(&fd_write);
96 FD_ZERO(&fd_exec); 134 FD_ZERO(&fd_exec);
97 135
98 int fd_max = 0; 136 int fd_max = 0;
99 137
100 // Ask libcurl for the set of file descriptors we should track on its 138 // Ask libcurl for the set of file descriptors we should track on its
101 // behalf. 139 // behalf.
102 CHECK_EQ(CURLM_OK, curl_multi_fdset(curl_multi_handle_, &fd_read, &fd_write, 140 CHECK_EQ(curl_multi_fdset(curl_multi_handle_, &fd_read, &fd_write,
103 &fd_exec, &fd_max)); 141 &fd_exec, &fd_max), CURLM_OK);
104 142
105 // We should iterate through all file descriptors up to libcurl's fd_max or 143 // We should iterate through all file descriptors up to libcurl's fd_max or
106 // the highest one we're tracking, whichever is larger 144 // the highest one we're tracking, whichever is larger
107 if (!io_channels_.empty()) 145 if (!io_channels_.empty())
108 fd_max = max(fd_max, io_channels_.rbegin()->first); 146 fd_max = max(fd_max, io_channels_.rbegin()->first);
109 147
110 // For each fd, if we're not tracking it, track it. If we are tracking it, 148 // For each fd, if we're not tracking it, track it. If we are tracking it,
111 // but libcurl doesn't care about it anymore, stop tracking it. 149 // but libcurl doesn't care about it anymore, stop tracking it.
112 // After this loop, there should be exactly as many GIOChannel objects 150 // After this loop, there should be exactly as many GIOChannel objects
113 // in io_channels_ as there are fds that we're tracking. 151 // in io_channels_ as there are fds that we're tracking.
114 for (int i = 0; i <= fd_max; i++) { 152 for (int i = 0; i <= fd_max; i++) {
115 if (!(FD_ISSET(i, &fd_read) || FD_ISSET(i, &fd_write) || 153 if (!(FD_ISSET(i, &fd_read) || FD_ISSET(i, &fd_write) ||
116 FD_ISSET(i, &fd_exec))) { 154 FD_ISSET(i, &fd_exec))) {
117 // if we have an outstanding io_channel, remove it 155 // if we have an outstanding io_channel, remove it
118 if (io_channels_.find(i) != io_channels_.end()) { 156 if (io_channels_.find(i) != io_channels_.end()) {
119 g_source_remove(io_channels_[i].second); 157 g_source_remove(io_channels_[i].second);
120 g_io_channel_unref(io_channels_[i].first); 158 g_io_channel_unref(io_channels_[i].first);
121 io_channels_.erase(io_channels_.find(i)); 159 io_channels_.erase(io_channels_.find(i));
122 } 160 }
123 continue; 161 continue;
124 } 162 }
125 // If we are already tracking this fd, continue. 163 // If we are already tracking this fd, continue.
126 if (io_channels_.find(i) != io_channels_.end()) 164 if (io_channels_.find(i) != io_channels_.end())
127 continue; 165 continue;
128 166
129 // We must track a new fd 167 // We must track a new fd
130 GIOChannel *io_channel = g_io_channel_unix_new(i); 168 GIOChannel *io_channel = g_io_channel_unix_new(i);
131 guint tag = g_io_add_watch( 169 guint tag = g_io_add_watch(
132 io_channel, 170 io_channel,
133 static_cast<GIOCondition>(G_IO_IN | G_IO_OUT | G_IO_PRI | 171 static_cast<GIOCondition>(G_IO_IN | G_IO_OUT | G_IO_PRI |
134 G_IO_ERR | G_IO_HUP), 172 G_IO_ERR | G_IO_HUP),
135 &StaticFDCallback, 173 &StaticFDCallback,
136 this); 174 this);
137 io_channels_[i] = make_pair(io_channel, tag); 175 io_channels_[i] = make_pair(io_channel, tag);
138 } 176 }
139 177
140 // Wet up a timeout callback for libcurl 178 // Wet up a timeout callback for libcurl
141 long ms = 0; 179 long ms = 0;
142 CHECK_EQ(CURLM_OK, curl_multi_timeout(curl_multi_handle_, &ms)); 180 CHECK_EQ(curl_multi_timeout(curl_multi_handle_, &ms), CURLM_OK);
143 if (ms < 0) { 181 if (ms < 0) {
144 // From http://curl.haxx.se/libcurl/c/curl_multi_timeout.html: 182 // From http://curl.haxx.se/libcurl/c/curl_multi_timeout.html:
145 // if libcurl returns a -1 timeout here, it just means that libcurl 183 // if libcurl returns a -1 timeout here, it just means that libcurl
146 // currently has no stored timeout value. You must not wait too long 184 // currently has no stored timeout value. You must not wait too long
147 // (more than a few seconds perhaps) before you call 185 // (more than a few seconds perhaps) before you call
148 // curl_multi_perform() again. 186 // curl_multi_perform() again.
149 ms = idle_ms_; 187 ms = idle_ms_;
150 } 188 }
151 if (timeout_source_) { 189 if (timeout_source_) {
152 g_source_destroy(timeout_source_); 190 g_source_destroy(timeout_source_);
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 241
204 for (IOChannels::iterator it = io_channels_.begin(); 242 for (IOChannels::iterator it = io_channels_.begin();
205 it != io_channels_.end(); ++it) { 243 it != io_channels_.end(); ++it) {
206 g_source_remove(it->second.second); 244 g_source_remove(it->second.second);
207 g_io_channel_unref(it->second.first); 245 g_io_channel_unref(it->second.first);
208 } 246 }
209 io_channels_.clear(); 247 io_channels_.clear();
210 248
211 if (curl_handle_) { 249 if (curl_handle_) {
212 if (curl_multi_handle_) { 250 if (curl_multi_handle_) {
213 CHECK_EQ(CURLM_OK, 251 CHECK_EQ(curl_multi_remove_handle(curl_multi_handle_, curl_handle_),
214 curl_multi_remove_handle(curl_multi_handle_, curl_handle_)); 252 CURLM_OK);
215 } 253 }
216 curl_easy_cleanup(curl_handle_); 254 curl_easy_cleanup(curl_handle_);
217 curl_handle_ = NULL; 255 curl_handle_ = NULL;
218 } 256 }
219 if (curl_multi_handle_) { 257 if (curl_multi_handle_) {
220 CHECK_EQ(CURLM_OK, curl_multi_cleanup(curl_multi_handle_)); 258 CHECK_EQ(curl_multi_cleanup(curl_multi_handle_), CURLM_OK);
221 curl_multi_handle_ = NULL; 259 curl_multi_handle_ = NULL;
222 } 260 }
223 transfer_in_progress_ = false; 261 transfer_in_progress_ = false;
224 } 262 }
225 263
226 } // namespace chromeos_update_engine 264 } // namespace chromeos_update_engine
OLDNEW
« no previous file with comments | « src/platform/update_engine/libcurl_http_fetcher.h ('k') | src/platform/update_engine/main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698