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. MultiRangeHttpFetcher(HttpFetcher * base_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) {} ~MultiRangeHttpFetcher()56 ~MultiRangeHttpFetcher() override {} 57 ClearRanges()58 void ClearRanges() { ranges_.clear(); } 59 AddRange(off_t offset,size_t size)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 AddRange(off_t offset)65 void AddRange(off_t offset) { ranges_.push_back(Range(offset)); } 66 67 // HttpFetcher overrides. 68 void SetOffset(off_t offset) override; 69 SetLength(size_t length)70 void SetLength(size_t length) override {} // unsupported UnsetLength()71 void UnsetLength() override {} 72 73 // Begins the transfer to the specified URL. 74 // State change: Stopped -> Downloading 75 // (corner case: Stopped -> Stopped for an empty request) 76 void BeginTransfer(const std::string& url) override; 77 78 // State change: Downloading -> Pending transfer ended 79 void TerminateTransfer() override; 80 SetHeader(const std::string & header_name,const std::string & header_value)81 void SetHeader(const std::string& header_name, 82 const std::string& header_value) override { 83 base_fetcher_->SetHeader(header_name, header_value); 84 } 85 Pause()86 void Pause() override { base_fetcher_->Pause(); } 87 Unpause()88 void Unpause() override { base_fetcher_->Unpause(); } 89 90 // These functions are overloaded in LibcurlHttp fetcher for testing purposes. set_idle_seconds(int seconds)91 void set_idle_seconds(int seconds) override { 92 base_fetcher_->set_idle_seconds(seconds); 93 } set_retry_seconds(int seconds)94 void set_retry_seconds(int seconds) override { 95 base_fetcher_->set_retry_seconds(seconds); 96 } 97 // TODO(deymo): Determine if this method should be virtual in HttpFetcher so 98 // this call is sent to the base_fetcher_. SetProxies(const std::deque<std::string> & proxies)99 virtual void SetProxies(const std::deque<std::string>& proxies) { 100 base_fetcher_->SetProxies(proxies); 101 } 102 GetBytesDownloaded()103 inline size_t GetBytesDownloaded() override { 104 return base_fetcher_->GetBytesDownloaded(); 105 } 106 set_low_speed_limit(int low_speed_bps,int low_speed_sec)107 void set_low_speed_limit(int low_speed_bps, int low_speed_sec) override { 108 base_fetcher_->set_low_speed_limit(low_speed_bps, low_speed_sec); 109 } 110 set_connect_timeout(int connect_timeout_seconds)111 void set_connect_timeout(int connect_timeout_seconds) override { 112 base_fetcher_->set_connect_timeout(connect_timeout_seconds); 113 } 114 set_max_retry_count(int max_retry_count)115 void set_max_retry_count(int max_retry_count) override { 116 base_fetcher_->set_max_retry_count(max_retry_count); 117 } 118 119 private: 120 // A range object defining the offset and length of a download chunk. Zero 121 // length indicates an unspecified end offset (note that it is impossible to 122 // request a zero-length range in HTTP). 123 class Range { 124 public: Range(off_t offset,size_t length)125 Range(off_t offset, size_t length) : offset_(offset), length_(length) {} Range(off_t offset)126 explicit Range(off_t offset) : offset_(offset), length_(0) {} 127 offset()128 inline off_t offset() const { return offset_; } length()129 inline size_t length() const { return length_; } 130 HasLength()131 inline bool HasLength() const { return (length_ > 0); } 132 133 std::string ToString() const; 134 135 private: 136 off_t offset_; 137 size_t length_; 138 }; 139 140 typedef std::vector<Range> RangesVect; 141 142 // State change: Stopped or Downloading -> Downloading 143 void StartTransfer(); 144 145 // HttpFetcherDelegate overrides. 146 // State change: Downloading -> Downloading or Pending transfer ended 147 bool ReceivedBytes(HttpFetcher* fetcher, 148 const void* bytes, 149 size_t length) override; 150 151 // State change: Pending transfer ended -> Stopped 152 void TransferEnded(HttpFetcher* fetcher, bool successful); 153 // These two call TransferEnded(): 154 void TransferComplete(HttpFetcher* fetcher, bool successful) override; 155 void TransferTerminated(HttpFetcher* fetcher) override; 156 157 void Reset(); 158 159 std::unique_ptr<HttpFetcher> base_fetcher_; 160 161 // If true, do not send any more data or TransferComplete to the delegate. 162 bool base_fetcher_active_; 163 164 // If true, the next fetcher needs to be started when TransferTerminated is 165 // received from the current fetcher. 166 bool pending_transfer_ended_; 167 168 // True if we are waiting for base fetcher to terminate b/c we are 169 // ourselves terminating. 170 bool terminating_; 171 172 RangesVect ranges_; 173 174 RangesVect::size_type current_index_; // index into ranges_ 175 size_t bytes_received_this_range_; 176 177 DISALLOW_COPY_AND_ASSIGN(MultiRangeHttpFetcher); 178 }; 179 180 } // namespace chromeos_update_engine 181 182 #endif // UPDATE_ENGINE_COMMON_MULTI_RANGE_HTTP_FETCHER_H_ 183