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