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