xref: /aosp_15_r20/external/federated-compute/fcp/client/http/curl/curl_api.h (revision 14675a029014e728ec732f129a32e299b2da0601)
1 /*
2  * Copyright 2022 Google LLC
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 #ifndef FCP_CLIENT_HTTP_CURL_CURL_API_H_
17 #define FCP_CLIENT_HTTP_CURL_CURL_API_H_
18 
19 #include <memory>
20 #include <string>
21 #include <type_traits>
22 
23 #include "absl/synchronization/mutex.h"
24 #include "curl/curl.h"
25 
26 namespace fcp::client::http::curl {
27 // An RAII wrapper around the libcurl easy handle, which works with one request.
28 // The class is not thread-safe.
29 class CurlEasyHandle {
30  public:
31   ~CurlEasyHandle();
32   CurlEasyHandle(const CurlEasyHandle&) = delete;
33   CurlEasyHandle& operator=(const CurlEasyHandle&) = delete;
34 
35   CURLcode GetInfo(CURLINFO info, curl_off_t* value) const;
36 
37   template <typename T, typename = std::enable_if_t<std::is_trivial_v<T>>>
SetOpt(CURLoption option,T value)38   CURLcode SetOpt(CURLoption option, T value) {
39     return curl_easy_setopt(easy_handle_, option, value);
40   }
SetOpt(CURLoption option,const std::string & value)41   CURLcode SetOpt(CURLoption option, const std::string& value) {
42     return SetOpt(option, value.c_str());
43   }
44 
45   // Converts the curl code into a human-readable form.
46   ABSL_MUST_USE_RESULT static std::string StrError(CURLcode code);
47 
48   // Returns the underlying curl handle.
49   ABSL_MUST_USE_RESULT CURL* GetEasyHandle() const;
50 
51  private:
52   friend class CurlApi;
53   CurlEasyHandle();
54   CURL* const easy_handle_;
55 };
56 
57 // An RAII wrapper around the libcurl multi handle, which is a bundle of easy
58 // requests that performs them in parallel in one thread. The class is not
59 // thread-safe.
60 class CurlMultiHandle {
61  public:
62   ~CurlMultiHandle();
63   CurlMultiHandle(const CurlMultiHandle&) = delete;
64   CurlMultiHandle& operator=(const CurlMultiHandle&) = delete;
65 
66   // Fetches the next message in the message queue.
67   CURLMsg* InfoRead(int* msgs_in_queue);
68 
69   // Add a new request to the bundle.
70   CURLMcode AddEasyHandle(CurlEasyHandle* easy_handle);
71 
72   // Remove the requests from the bundle. It will cancel an unfinished request,
73   // but it will not delete the easy handle.
74   CURLMcode RemoveEasyHandle(CurlEasyHandle* easy_handle);
75 
76   // Performs all active tasks and returns.
77   CURLMcode Perform(int* num_running_handles);
78 
79   // Waits for a new job
80   CURLMcode Poll(curl_waitfd extra_fds[], unsigned int extra_nfds,
81                  int timeout_ms, int* numfds);
82 
83   // Converts the curl code into a human-readable form.
84   ABSL_MUST_USE_RESULT static std::string StrError(CURLMcode code);
85 
86  private:
87   friend class CurlApi;
88   CurlMultiHandle();
89   CURLM* const multi_handle_;
90 };
91 
92 // An RAII wrapper around global initialization for libcurl. It forces the user
93 // to create it first, so the initialization can be made, on which handles
94 // depend. The class needs to be created only once, and its methods are
95 // thread-safe.
96 class CurlApi {
97  public:
98   CurlApi();
99   ~CurlApi();
100   CurlApi(const CurlApi&) = delete;
101   CurlApi& operator=(const CurlApi&) = delete;
102 
103   ABSL_MUST_USE_RESULT std::unique_ptr<CurlEasyHandle> CreateEasyHandle() const;
104   ABSL_MUST_USE_RESULT std::unique_ptr<CurlMultiHandle> CreateMultiHandle()
105       const;
106 
107  private:
108   mutable absl::Mutex mutex_;
109 };
110 
111 }  // namespace fcp::client::http::curl
112 
113 #endif  // FCP_CLIENT_HTTP_CURL_CURL_API_H_
114