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