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