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