Home | History | Annotate | Download | only in common
      1 //
      2 // Copyright (C) 2009 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_HTTP_FETCHER_H_
     18 #define UPDATE_ENGINE_COMMON_HTTP_FETCHER_H_
     19 
     20 #include <deque>
     21 #include <string>
     22 #include <vector>
     23 
     24 #include <base/callback.h>
     25 #include <base/logging.h>
     26 #include <base/macros.h>
     27 #include <brillo/message_loops/message_loop.h>
     28 
     29 #include "update_engine/common/http_common.h"
     30 #include "update_engine/proxy_resolver.h"
     31 
     32 // This class is a simple wrapper around an HTTP library (libcurl). We can
     33 // easily mock out this interface for testing.
     34 
     35 // Implementations of this class should use asynchronous i/o. They can access
     36 // the MessageLoop to request callbacks when timers or file descriptors change.
     37 
     38 namespace chromeos_update_engine {
     39 
     40 class HttpFetcherDelegate;
     41 
     42 class HttpFetcher {
     43  public:
     44   // |proxy_resolver| is the resolver that will be consulted for proxy
     45   // settings. It may be null, in which case direct connections will
     46   // be used. Does not take ownership of the resolver.
     47   explicit HttpFetcher(ProxyResolver* proxy_resolver)
     48       : post_data_set_(false),
     49         http_response_code_(0),
     50         delegate_(nullptr),
     51         proxies_(1, kNoProxy),
     52         proxy_resolver_(proxy_resolver),
     53         callback_(nullptr) {}
     54   virtual ~HttpFetcher();
     55 
     56   void set_delegate(HttpFetcherDelegate* delegate) { delegate_ = delegate; }
     57   HttpFetcherDelegate* delegate() const { return delegate_; }
     58   int http_response_code() const { return http_response_code_; }
     59 
     60   // Optional: Post data to the server. The HttpFetcher should make a copy
     61   // of this data and upload it via HTTP POST during the transfer. The type of
     62   // the data is necessary for properly setting the Content-Type HTTP header.
     63   void SetPostData(const void* data, size_t size, HttpContentType type);
     64 
     65   // Same without a specified Content-Type.
     66   void SetPostData(const void* data, size_t size);
     67 
     68   // Proxy methods to set the proxies, then to pop them off.
     69   // Returns true on success.
     70   bool ResolveProxiesForUrl(const std::string& url,
     71                             const base::Closure& callback);
     72 
     73   void SetProxies(const std::deque<std::string>& proxies) {
     74     proxies_ = proxies;
     75   }
     76   const std::string& GetCurrentProxy() const {
     77     return proxies_.front();
     78   }
     79   bool HasProxy() const { return !proxies_.empty(); }
     80   void PopProxy() { proxies_.pop_front(); }
     81 
     82   // Downloading should resume from this offset
     83   virtual void SetOffset(off_t offset) = 0;
     84 
     85   // Set/unset the length of the range to be downloaded.
     86   virtual void SetLength(size_t length) = 0;
     87   virtual void UnsetLength() = 0;
     88 
     89   // Begins the transfer to the specified URL. This fetcher instance should not
     90   // be destroyed until either TransferComplete, or TransferTerminated is
     91   // called.
     92   virtual void BeginTransfer(const std::string& url) = 0;
     93 
     94   // Aborts the transfer. The transfer may not abort right away -- delegate's
     95   // TransferTerminated() will be called when the transfer is actually done.
     96   virtual void TerminateTransfer() = 0;
     97 
     98   // Add or update a custom header to be sent with every request. If the same
     99   // |header_name| is passed twice, the second |header_value| would override the
    100   // previous value.
    101   virtual void SetHeader(const std::string& header_name,
    102                          const std::string& header_value) = 0;
    103 
    104   // If data is coming in too quickly, you can call Pause() to pause the
    105   // transfer. The delegate will not have ReceivedBytes() called while
    106   // an HttpFetcher is paused.
    107   virtual void Pause() = 0;
    108 
    109   // Used to unpause an HttpFetcher and let the bytes stream in again.
    110   // If a delegate is set, ReceivedBytes() may be called on it before
    111   // Unpause() returns
    112   virtual void Unpause() = 0;
    113 
    114   // These two function are overloaded in LibcurlHttp fetcher to speed
    115   // testing.
    116   virtual void set_idle_seconds(int seconds) {}
    117   virtual void set_retry_seconds(int seconds) {}
    118 
    119   // Sets the values used to time out the connection if the transfer
    120   // rate is less than |low_speed_bps| bytes/sec for more than
    121   // |low_speed_sec| seconds.
    122   virtual void set_low_speed_limit(int low_speed_bps, int low_speed_sec) = 0;
    123 
    124   // Sets the connect timeout, e.g. the maximum amount of time willing
    125   // to wait for establishing a connection to the server.
    126   virtual void set_connect_timeout(int connect_timeout_seconds) = 0;
    127 
    128   // Sets the number of allowed retries.
    129   virtual void set_max_retry_count(int max_retry_count) = 0;
    130 
    131   // Get the total number of bytes downloaded by fetcher.
    132   virtual size_t GetBytesDownloaded() = 0;
    133 
    134   ProxyResolver* proxy_resolver() const { return proxy_resolver_; }
    135 
    136  protected:
    137   // Cancels a proxy resolution in progress. The callback passed to
    138   // ResolveProxiesForUrl() will not be called. Returns whether there was a
    139   // pending proxy resolution to be canceled.
    140   bool CancelProxyResolution();
    141 
    142   // The URL we're actively fetching from
    143   std::string url_;
    144 
    145   // POST data for the transfer, and whether or not it was ever set
    146   bool post_data_set_;
    147   brillo::Blob post_data_;
    148   HttpContentType post_content_type_;
    149 
    150   // The server's HTTP response code from the last transfer. This
    151   // field should be set to 0 when a new transfer is initiated, and
    152   // set to the response code when the transfer is complete.
    153   int http_response_code_;
    154 
    155   // The delegate; may be null.
    156   HttpFetcherDelegate* delegate_;
    157 
    158   // Proxy servers
    159   std::deque<std::string> proxies_;
    160 
    161   ProxyResolver* const proxy_resolver_;
    162 
    163   // The ID of the idle callback, used when we have no proxy resolver.
    164   brillo::MessageLoop::TaskId no_resolver_idle_id_{
    165       brillo::MessageLoop::kTaskIdNull};
    166 
    167   // Callback for when we are resolving proxies
    168   std::unique_ptr<base::Closure> callback_;
    169 
    170  private:
    171   // Callback from the proxy resolver
    172   void ProxiesResolved(const std::deque<std::string>& proxies);
    173 
    174   // Callback used to run the proxy resolver callback when there is no
    175   // |proxy_resolver_|.
    176   void NoProxyResolverCallback();
    177 
    178   // Stores the ongoing proxy request id if there is one, otherwise
    179   // kProxyRequestIdNull.
    180   ProxyRequestId proxy_request_{kProxyRequestIdNull};
    181 
    182   DISALLOW_COPY_AND_ASSIGN(HttpFetcher);
    183 };
    184 
    185 // Interface for delegates
    186 class HttpFetcherDelegate {
    187  public:
    188   virtual ~HttpFetcherDelegate() = default;
    189 
    190   // Called every time bytes are received.
    191   virtual void ReceivedBytes(HttpFetcher* fetcher,
    192                              const void* bytes,
    193                              size_t length) = 0;
    194 
    195   // Called if the fetcher seeks to a particular offset.
    196   virtual void SeekToOffset(off_t offset) {}
    197 
    198   // When a transfer has completed, exactly one of these two methods will be
    199   // called. TransferTerminated is called when the transfer has been aborted
    200   // through TerminateTransfer. TransferComplete is called in all other
    201   // situations. It's OK to destroy the |fetcher| object in this callback.
    202   virtual void TransferComplete(HttpFetcher* fetcher, bool successful) = 0;
    203   virtual void TransferTerminated(HttpFetcher* fetcher) {}
    204 };
    205 
    206 }  // namespace chromeos_update_engine
    207 
    208 #endif  // UPDATE_ENGINE_COMMON_HTTP_FETCHER_H_
    209