1 // Copyright 2014 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_CURL_H_
6 #define LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_CURL_H_
7 
8 #include <map>
9 #include <memory>
10 #include <string>
11 #include <utility>
12 
13 #include <base/location.h>
14 #include <base/memory/weak_ptr.h>
15 #include <brillo/brillo_export.h>
16 #include <brillo/http/curl_api.h>
17 #include <brillo/http/http_transport.h>
18 
19 namespace brillo {
20 namespace http {
21 namespace curl {
22 
23 class Connection;
24 
25 ///////////////////////////////////////////////////////////////////////////////
26 // An implementation of http::Transport that uses libcurl for
27 // HTTP communications. This class (as http::Transport base)
28 // is used by http::Request and http::Response classes to provide HTTP
29 // functionality to the clients.
30 // See http_transport.h for more details.
31 ///////////////////////////////////////////////////////////////////////////////
32 class BRILLO_EXPORT Transport : public http::Transport {
33  public:
34   // Constructs the transport using the current message loop for async
35   // operations.
36   explicit Transport(const std::shared_ptr<CurlInterface>& curl_interface);
37   // Creates a transport object using a proxy.
38   // |proxy| is of the form [protocol://][user:password@]host[:port].
39   // If not defined, protocol is assumed to be http://.
40   Transport(const std::shared_ptr<CurlInterface>& curl_interface,
41             const std::string& proxy);
42   ~Transport() override;
43 
44   // Overrides from http::Transport.
45   std::shared_ptr<http::Connection> CreateConnection(
46       const std::string& url,
47       const std::string& method,
48       const HeaderList& headers,
49       const std::string& user_agent,
50       const std::string& referer,
51       brillo::ErrorPtr* error) override;
52 
53   void RunCallbackAsync(const base::Location& from_here,
54                         const base::Closure& callback) override;
55 
56   RequestID StartAsyncTransfer(http::Connection* connection,
57                                const SuccessCallback& success_callback,
58                                const ErrorCallback& error_callback) override;
59 
60   bool CancelRequest(RequestID request_id) override;
61 
62   void SetDefaultTimeout(base::TimeDelta timeout) override;
63 
64   void SetLocalIpAddress(const std::string& ip_address) override;
65 
66   void UseDefaultCertificate() override;
67 
68   void UseCustomCertificate(Certificate cert) override;
69 
70   void ResolveHostToIp(const std::string& host,
71                        uint16_t port,
72                        const std::string& ip_address) override;
73 
74   // Helper methods to convert CURL error codes (CURLcode and CURLMcode)
75   // into brillo::Error object.
76   static void AddEasyCurlError(brillo::ErrorPtr* error,
77                                const base::Location& location,
78                                CURLcode code,
79                                CurlInterface* curl_interface);
80 
81   static void AddMultiCurlError(brillo::ErrorPtr* error,
82                                 const base::Location& location,
83                                 CURLMcode code,
84                                 CurlInterface* curl_interface);
85 
86  protected:
87   void ClearHost() override;
88 
89  private:
90   // Forward-declaration of internal implementation structures.
91   struct AsyncRequestData;
92   class SocketPollData;
93 
94   // Initializes CURL for async operation.
95   bool SetupAsyncCurl(brillo::ErrorPtr* error);
96 
97   // Stops CURL's async operations.
98   void ShutDownAsyncCurl();
99 
100   // Handles all pending async messages from CURL.
101   void ProcessAsyncCurlMessages();
102 
103   // Processes the transfer completion message (success or failure).
104   void OnTransferComplete(http::curl::Connection* connection,
105                           CURLcode code);
106 
107   // Cleans up internal data for a completed/canceled asynchronous operation
108   // on a connection.
109   void CleanAsyncConnection(http::curl::Connection* connection);
110 
111   // Called after a timeout delay requested by CURL has elapsed.
112   void OnTimer();
113 
114   // Callback for CURL to handle curl_socket_callback() notifications.
115   // The parameters correspond to those of curl_socket_callback().
116   static int MultiSocketCallback(CURL* easy,
117                                  curl_socket_t s,
118                                  int what,
119                                  void* userp,
120                                  void* socketp);
121 
122   // Callback for CURL to handle curl_multi_timer_callback() notifications.
123   // The parameters correspond to those of curl_multi_timer_callback().
124   // CURL actually uses "long" types in callback signatures, so we must comply.
125   static int MultiTimerCallback(CURLM* multi,
126                                 long timeout_ms,  // NOLINT(runtime/int)
127                                 void* userp);
128 
129   std::shared_ptr<CurlInterface> curl_interface_;
130   std::string proxy_;
131   // CURL "multi"-handle for processing requests on multiple connections.
132   CURLM* curl_multi_handle_{nullptr};
133   // A map to find a corresponding Connection* using a request ID.
134   std::map<RequestID, Connection*> request_id_map_;
135   // Stores the connection-specific asynchronous data (such as the success
136   // and error callbacks that need to be called at the end of the async
137   // operation).
138   std::map<Connection*, std::unique_ptr<AsyncRequestData>> async_requests_;
139   // Internal data associated with in-progress asynchronous operations.
140   std::map<std::pair<CURL*, curl_socket_t>, SocketPollData*> poll_data_map_;
141   // The last request ID used for asynchronous operations.
142   RequestID last_request_id_{0};
143   // The connection timeout for the requests made.
144   base::TimeDelta connection_timeout_;
145   std::string ip_address_;
146   base::FilePath certificate_path_;
147   curl_slist* host_list_{nullptr};
148 
149   base::WeakPtrFactory<Transport> weak_ptr_factory_for_timer_{this};
150   base::WeakPtrFactory<Transport> weak_ptr_factory_{this};
151   DISALLOW_COPY_AND_ASSIGN(Transport);
152 };
153 
154 }  // namespace curl
155 }  // namespace http
156 }  // namespace brillo
157 
158 #endif  // LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_CURL_H_
159