• Home
  • History
  • Annotate
  • 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(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) {
66      ranges_.push_back(Range(offset));
67    }
68  
69    // HttpFetcher overrides.
SetOffset(off_t offset)70    void SetOffset(off_t offset) override {}  // for now, doesn't support this
71  
SetLength(size_t length)72    void SetLength(size_t length) override {}  // unsupported
UnsetLength()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  
SetHeader(const std::string & header_name,const std::string & header_value)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  
Pause()88    void Pause() override { base_fetcher_->Pause(); }
89  
Unpause()90    void Unpause() override { base_fetcher_->Unpause(); }
91  
92    // These functions are overloaded in LibcurlHttp fetcher for testing purposes.
set_idle_seconds(int seconds)93    void set_idle_seconds(int seconds) override {
94      base_fetcher_->set_idle_seconds(seconds);
95    }
set_retry_seconds(int seconds)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_.
SetProxies(const std::deque<std::string> & proxies)101    virtual void SetProxies(const std::deque<std::string>& proxies) {
102      base_fetcher_->SetProxies(proxies);
103    }
104  
GetBytesDownloaded()105    inline size_t GetBytesDownloaded() override {
106      return base_fetcher_->GetBytesDownloaded();
107    }
108  
set_low_speed_limit(int low_speed_bps,int low_speed_sec)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  
set_connect_timeout(int connect_timeout_seconds)113    void set_connect_timeout(int connect_timeout_seconds) override {
114      base_fetcher_->set_connect_timeout(connect_timeout_seconds);
115    }
116  
set_max_retry_count(int max_retry_count)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:
Range(off_t offset,size_t length)127      Range(off_t offset, size_t length) : offset_(offset), length_(length) {}
Range(off_t offset)128      explicit Range(off_t offset) : offset_(offset), length_(0) {}
129  
offset()130      inline off_t offset() const { return offset_; }
length()131      inline size_t length() const { return length_; }
132  
HasLength()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