• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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