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

Unified Diff: multi_http_fetcher.h

Issue 3591018: AU: MultiHttpFetcher, an HttpFetcher for specific byte ranges (Closed) Base URL: ssh://git@chromiumos-git/update_engine.git
Patch Set: fixes for rewview Created 10 years, 2 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mock_http_fetcher.h ('k') | test_http_server.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: multi_http_fetcher.h
diff --git a/multi_http_fetcher.h b/multi_http_fetcher.h
new file mode 100644
index 0000000000000000000000000000000000000000..cee7de03bf8d4bb138a384f1eaf46b7f4b7772bd
--- /dev/null
+++ b/multi_http_fetcher.h
@@ -0,0 +1,189 @@
+// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_MULTI_HTTP_FETCHER_H__
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_MULTI_HTTP_FETCHER_H__
+
+#include <tr1/memory>
+#include <utility>
+#include <vector>
+
+#include "update_engine/http_fetcher.h"
+
+// This class is a simple wrapper around an HttpFetcher. The client
+// specifies a vector of byte ranges. MultiHttpFetcher will fetch bytes
+// from those offsets. Pass -1 as a length to specify unlimited length.
+// It really only would make sense for the last range specified to have
+// unlimited length.
+
+namespace chromeos_update_engine {
+
+template<typename BaseHttpFetcher>
+class MultiHttpFetcher : public HttpFetcher, public HttpFetcherDelegate {
+ public:
+ typedef std::vector<std::pair<off_t, off_t> > RangesVect;
+
+ MultiHttpFetcher()
+ : sent_transfer_complete_(false),
+ current_index_(0),
+ bytes_received_this_fetcher_(0) {}
+ ~MultiHttpFetcher() {}
+
+ void set_ranges(const RangesVect& ranges) {
+ ranges_ = ranges;
+ fetchers_.resize(ranges_.size()); // Allocate the fetchers
+ for (typename std::vector<std::tr1::shared_ptr<BaseHttpFetcher>
+ >::iterator it = fetchers_.begin(), e = fetchers_.end();
+ it != e; ++it) {
+ (*it) = std::tr1::shared_ptr<BaseHttpFetcher>(new BaseHttpFetcher);
+ (*it)->set_delegate(this);
+ }
+ }
+
+ void SetOffset(off_t offset) {} // for now, doesn't support this
+
+ // Begins the transfer to the specified URL.
+ void BeginTransfer(const std::string& url) {
+ url_ = url;
+ if (ranges_.empty()) {
+ if (delegate_)
+ delegate_->TransferComplete(this, true);
+ return;
+ }
+ current_index_ = 0;
+ LOG(INFO) << "starting first transfer";
+ StartTransfer();
+ }
+
+ void TerminateTransfer() {
+ if (current_index_ < fetchers_.size())
+ fetchers_[current_index_]->TerminateTransfer();
+ current_index_ = ranges_.size();
+ sent_transfer_complete_ = true; // a fib
+ }
+
+ void Pause() {
+ if (current_index_ < fetchers_.size())
+ fetchers_[current_index_]->Pause();
+ }
+
+ void Unpause() {
+ if (current_index_ < fetchers_.size())
+ fetchers_[current_index_]->Unpause();
+ }
+
+ // These two function are overloaded in LibcurlHttp fetcher to speed
+ // testing.
+ void set_idle_seconds(int seconds) {
+ for (typename std::vector<std::tr1::shared_ptr<BaseHttpFetcher> >::iterator
+ it = fetchers_.begin(),
+ e = fetchers_.end(); it != e; ++it) {
+ (*it)->set_idle_seconds(seconds);
+ }
+ }
+ void set_retry_seconds(int seconds) {
+ for (typename std::vector<std::tr1::shared_ptr<BaseHttpFetcher> >::iterator
+ it = fetchers_.begin(),
+ e = fetchers_.end(); it != e; ++it) {
+ (*it)->set_retry_seconds(seconds);
+ }
+ }
+
+ private:
+ void SendTransferComplete(HttpFetcher* fetcher, bool successful) {
+ if (sent_transfer_complete_)
+ return;
+ LOG(INFO) << "Sending transfer complete";
+ sent_transfer_complete_ = true;
+ http_response_code_ = fetcher->http_response_code();
+ if (delegate_)
+ delegate_->TransferComplete(this, successful);
+ }
+
+ void StartTransfer() {
+ if (current_index_ >= ranges_.size()) {
+ return;
+ }
+ LOG(INFO) << "Starting a transfer";
+ bytes_received_this_fetcher_ = 0;
+ fetchers_[current_index_]->SetOffset(ranges_[current_index_].first);
+ fetchers_[current_index_]->BeginTransfer(url_);
+ }
+
+ void ReceivedBytes(HttpFetcher* fetcher,
+ const char* bytes,
+ int length) {
+ if (current_index_ >= ranges_.size())
+ return;
+ if (fetcher != fetchers_[current_index_].get()) {
+ LOG(WARNING) << "Received bytes from invalid fetcher";
+ return;
+ }
+ off_t next_size = length;
+ if (ranges_[current_index_].second >= 0) {
+ next_size = std::min(next_size,
+ ranges_[current_index_].second -
+ bytes_received_this_fetcher_);
+ }
+ LOG_IF(WARNING, next_size <= 0) << "Asked to write length <= 0";
+ if (delegate_)
+ delegate_->ReceivedBytes(this, bytes, next_size);
+ bytes_received_this_fetcher_ += length;
+ if (ranges_[current_index_].second >= 0 &&
+ bytes_received_this_fetcher_ >= ranges_[current_index_].second) {
+ fetchers_[current_index_]->TerminateTransfer();
+ current_index_++;
+ if (current_index_ == ranges_.size()) {
+ SendTransferComplete(fetchers_[current_index_ - 1].get(), true);
+ } else {
+ StartTransfer();
+ }
+ }
+ }
+
+ void TransferComplete(HttpFetcher* fetcher, bool successful) {
+ LOG(INFO) << "Received transfer complete";
+ if (current_index_ >= ranges_.size()) {
+ SendTransferComplete(fetcher, true);
+ return;
+ }
+
+ if (ranges_[current_index_].second < 0) {
+ // We're done with the current operation
+ current_index_++;
+ if (current_index_ >= ranges_.size() || !successful) {
+ SendTransferComplete(fetcher, successful);
+ } else {
+ // Do the next transfer
+ StartTransfer();
+ }
+ return;
+ }
+
+ if (bytes_received_this_fetcher_ < ranges_[current_index_].second) {
+ LOG(WARNING) << "Received insufficient bytes from fetcher. "
+ << "Ending early";
+ SendTransferComplete(fetcher, false);
+ return;
+ } else {
+ LOG(INFO) << "Got spurious TransferComplete. Ingoring.";
+ }
+ }
+
+ // If true, do not send any more data or TransferComplete to the delegate.
+ bool sent_transfer_complete_;
+
+ RangesVect ranges_;
+ std::vector<std::tr1::shared_ptr<BaseHttpFetcher> > fetchers_;
+
+ RangesVect::size_type current_index_; // index into ranges_, fetchers_
+ off_t bytes_received_this_fetcher_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MultiHttpFetcher);
+};
+
+} // namespace chromeos_update_engine
+
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_MULTI_HTTP_FETCHER_H__
« no previous file with comments | « mock_http_fetcher.h ('k') | test_http_server.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698