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 tracked_objects::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   // Helper methods to convert CURL error codes (CURLcode and CURLMcode)
63   // into brillo::Error object.
64   static void AddEasyCurlError(brillo::ErrorPtr* error,
65                                const tracked_objects::Location& location,
66                                CURLcode code,
67                                CurlInterface* curl_interface);
68 
69   static void AddMultiCurlError(brillo::ErrorPtr* error,
70                                 const tracked_objects::Location& location,
71                                 CURLMcode code,
72                                 CurlInterface* curl_interface);
73 
74  private:
75   // Forward-declaration of internal implementation structures.
76   struct AsyncRequestData;
77   class SocketPollData;
78 
79   // Initializes CURL for async operation.
80   bool SetupAsyncCurl(brillo::ErrorPtr* error);
81 
82   // Stops CURL's async operations.
83   void ShutDownAsyncCurl();
84 
85   // Handles all pending async messages from CURL.
86   void ProcessAsyncCurlMessages();
87 
88   // Processes the transfer completion message (success or failure).
89   void OnTransferComplete(http::curl::Connection* connection,
90                           CURLcode code);
91 
92   // Cleans up internal data for a completed/canceled asynchronous operation
93   // on a connection.
94   void CleanAsyncConnection(http::curl::Connection* connection);
95 
96   // Called after a timeout delay requested by CURL has elapsed.
97   void OnTimer();
98 
99   // Callback for CURL to handle curl_socket_callback() notifications.
100   // The parameters correspond to those of curl_socket_callback().
101   static int MultiSocketCallback(CURL* easy,
102                                  curl_socket_t s,
103                                  int what,
104                                  void* userp,
105                                  void* socketp);
106 
107   // Callback for CURL to handle curl_multi_timer_callback() notifications.
108   // The parameters correspond to those of curl_multi_timer_callback().
109   // CURL actually uses "long" types in callback signatures, so we must comply.
110   static int MultiTimerCallback(CURLM* multi,
111                                 long timeout_ms,  // NOLINT(runtime/int)
112                                 void* userp);
113 
114   std::shared_ptr<CurlInterface> curl_interface_;
115   std::string proxy_;
116   // CURL "multi"-handle for processing requests on multiple connections.
117   CURLM* curl_multi_handle_{nullptr};
118   // A map to find a corresponding Connection* using a request ID.
119   std::map<RequestID, Connection*> request_id_map_;
120   // Stores the connection-specific asynchronous data (such as the success
121   // and error callbacks that need to be called at the end of the async
122   // operation).
123   std::map<Connection*, std::unique_ptr<AsyncRequestData>> async_requests_;
124   // Internal data associated with in-progress asynchronous operations.
125   std::map<std::pair<CURL*, curl_socket_t>, SocketPollData*> poll_data_map_;
126   // The last request ID used for asynchronous operations.
127   RequestID last_request_id_{0};
128   // The connection timeout for the requests made.
129   base::TimeDelta connection_timeout_;
130 
131   base::WeakPtrFactory<Transport> weak_ptr_factory_for_timer_{this};
132   base::WeakPtrFactory<Transport> weak_ptr_factory_{this};
133   DISALLOW_COPY_AND_ASSIGN(Transport);
134 };
135 
136 }  // namespace curl
137 }  // namespace http
138 }  // namespace brillo
139 
140 #endif  // LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_CURL_H_
141