1 // 2 // Copyright (C) 2010 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #ifndef UPDATE_ENGINE_COMMON_MULTI_RANGE_HTTP_FETCHER_H_ 18 #define UPDATE_ENGINE_COMMON_MULTI_RANGE_HTTP_FETCHER_H_ 19 20 #include <deque> 21 #include <memory> 22 #include <string> 23 #include <utility> 24 #include <vector> 25 26 #include "update_engine/common/http_fetcher.h" 27 28 // This class is a simple wrapper around an HttpFetcher. The client 29 // specifies a vector of byte ranges. MultiRangeHttpFetcher will fetch bytes 30 // from those offsets, using the same bash fetcher for all ranges. Thus, the 31 // fetcher must support beginning a transfer after one has stopped. Pass -1 32 // as a length to specify unlimited length. It really only would make sense 33 // for the last range specified to have unlimited length, tho it is legal for 34 // other entries to have unlimited length. 35 36 // There are three states a MultiRangeHttpFetcher object will be in: 37 // - Stopped (start state) 38 // - Downloading 39 // - Pending transfer ended 40 // Various functions below that might change state indicate possible 41 // state changes. 42 43 namespace chromeos_update_engine { 44 45 class MultiRangeHttpFetcher : public HttpFetcher, public HttpFetcherDelegate { 46 public: 47 // Takes ownership of the passed in fetcher. 48 explicit MultiRangeHttpFetcher(HttpFetcher* base_fetcher) 49 : HttpFetcher(base_fetcher->proxy_resolver()), 50 base_fetcher_(base_fetcher), 51 base_fetcher_active_(false), 52 pending_transfer_ended_(false), 53 terminating_(false), 54 current_index_(0), 55 bytes_received_this_range_(0) {} 56 ~MultiRangeHttpFetcher() override {} 57 58 void ClearRanges() { ranges_.clear(); } 59 60 void AddRange(off_t offset, size_t size) { 61 CHECK_GT(size, static_cast<size_t>(0)); 62 ranges_.push_back(Range(offset, size)); 63 } 64 65 void AddRange(off_t offset) { 66 ranges_.push_back(Range(offset)); 67 } 68 69 // HttpFetcher overrides. 70 void SetOffset(off_t offset) override {} // for now, doesn't support this 71 72 void SetLength(size_t length) override {} // unsupported 73 void UnsetLength() override {} 74 75 // Begins the transfer to the specified URL. 76 // State change: Stopped -> Downloading 77 // (corner case: Stopped -> Stopped for an empty request) 78 void BeginTransfer(const std::string& url) override; 79 80 // State change: Downloading -> Pending transfer ended 81 void TerminateTransfer() override; 82 83 void SetHeader(const std::string& header_name, 84 const std::string& header_value) override { 85 base_fetcher_->SetHeader(header_name, header_value); 86 } 87 88 void Pause() override { base_fetcher_->Pause(); } 89 90 void Unpause() override { base_fetcher_->Unpause(); } 91 92 // These functions are overloaded in LibcurlHttp fetcher for testing purposes. 93 void set_idle_seconds(int seconds) override { 94 base_fetcher_->set_idle_seconds(seconds); 95 } 96 void set_retry_seconds(int seconds) override { 97 base_fetcher_->set_retry_seconds(seconds); 98 } 99 // TODO(deymo): Determine if this method should be virtual in HttpFetcher so 100 // this call is sent to the base_fetcher_. 101 virtual void SetProxies(const std::deque<std::string>& proxies) { 102 base_fetcher_->SetProxies(proxies); 103 } 104 105 inline size_t GetBytesDownloaded() override { 106 return base_fetcher_->GetBytesDownloaded(); 107 } 108 109 void set_low_speed_limit(int low_speed_bps, int low_speed_sec) override { 110 base_fetcher_->set_low_speed_limit(low_speed_bps, low_speed_sec); 111 } 112 113 void set_connect_timeout(int connect_timeout_seconds) override { 114 base_fetcher_->set_connect_timeout(connect_timeout_seconds); 115 } 116 117 void set_max_retry_count(int max_retry_count) override { 118 base_fetcher_->set_max_retry_count(max_retry_count); 119 } 120 121 private: 122 // A range object defining the offset and length of a download chunk. Zero 123 // length indicates an unspecified end offset (note that it is impossible to 124 // request a zero-length range in HTTP). 125 class Range { 126 public: 127 Range(off_t offset, size_t length) : offset_(offset), length_(length) {} 128 explicit Range(off_t offset) : offset_(offset), length_(0) {} 129 130 inline off_t offset() const { return offset_; } 131 inline size_t length() const { return length_; } 132 133 inline bool HasLength() const { return (length_ > 0); } 134 135 std::string ToString() const; 136 137 private: 138 off_t offset_; 139 size_t length_; 140 }; 141 142 typedef std::vector<Range> RangesVect; 143 144 // State change: Stopped or Downloading -> Downloading 145 void StartTransfer(); 146 147 // HttpFetcherDelegate overrides. 148 // State change: Downloading -> Downloading or Pending transfer ended 149 void ReceivedBytes(HttpFetcher* fetcher, 150 const void* bytes, 151 size_t length) override; 152 153 // State change: Pending transfer ended -> Stopped 154 void TransferEnded(HttpFetcher* fetcher, bool successful); 155 // These two call TransferEnded(): 156 void TransferComplete(HttpFetcher* fetcher, bool successful) override; 157 void TransferTerminated(HttpFetcher* fetcher) override; 158 159 void Reset(); 160 161 std::unique_ptr<HttpFetcher> base_fetcher_; 162 163 // If true, do not send any more data or TransferComplete to the delegate. 164 bool base_fetcher_active_; 165 166 // If true, the next fetcher needs to be started when TransferTerminated is 167 // received from the current fetcher. 168 bool pending_transfer_ended_; 169 170 // True if we are waiting for base fetcher to terminate b/c we are 171 // ourselves terminating. 172 bool terminating_; 173 174 RangesVect ranges_; 175 176 RangesVect::size_type current_index_; // index into ranges_ 177 size_t bytes_received_this_range_; 178 179 DISALLOW_COPY_AND_ASSIGN(MultiRangeHttpFetcher); 180 }; 181 182 } // namespace chromeos_update_engine 183 184 #endif // UPDATE_ENGINE_COMMON_MULTI_RANGE_HTTP_FETCHER_H_ 185