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 #include <brillo/http/curl_api.h>
6 
7 #include <base/logging.h>
8 
9 namespace brillo {
10 namespace http {
11 
12 namespace {
13 
14 static_assert(CURLOPTTYPE_LONG == 0 &&
15               CURLOPTTYPE_OBJECTPOINT == 10000 &&
16               CURLOPTTYPE_FUNCTIONPOINT == 20000 &&
17               CURLOPTTYPE_OFF_T == 30000,
18               "CURL option types are expected to be multiples of 10000");
19 
VerifyOptionType(CURLoption option,int expected_type)20 inline bool VerifyOptionType(CURLoption option, int expected_type) {
21   int option_type = (static_cast<int>(option) / 10000) * 10000;
22   return (option_type == expected_type);
23 }
24 
25 }  // anonymous namespace
26 
CurlApi()27 CurlApi::CurlApi() {
28   curl_global_init(CURL_GLOBAL_ALL);
29 }
30 
~CurlApi()31 CurlApi::~CurlApi() {
32   curl_global_cleanup();
33 }
34 
EasyInit()35 CURL* CurlApi::EasyInit() {
36   return curl_easy_init();
37 }
38 
EasyCleanup(CURL * curl)39 void CurlApi::EasyCleanup(CURL* curl) {
40   curl_easy_cleanup(curl);
41 }
42 
EasySetOptInt(CURL * curl,CURLoption option,int value)43 CURLcode CurlApi::EasySetOptInt(CURL* curl, CURLoption option, int value) {
44   CHECK(VerifyOptionType(option, CURLOPTTYPE_LONG))
45       << "Only options that expect a LONG data type must be specified here";
46   // CURL actually uses "long" type, so have to make sure we feed it what it
47   // expects.
48   // NOLINTNEXTLINE(runtime/int)
49   return curl_easy_setopt(curl, option, static_cast<long>(value));
50 }
51 
EasySetOptStr(CURL * curl,CURLoption option,const std::string & value)52 CURLcode CurlApi::EasySetOptStr(CURL* curl,
53                                 CURLoption option,
54                                 const std::string& value) {
55   CHECK(VerifyOptionType(option, CURLOPTTYPE_OBJECTPOINT))
56       << "Only options that expect a STRING data type must be specified here";
57   return curl_easy_setopt(curl, option, value.c_str());
58 }
59 
EasySetOptPtr(CURL * curl,CURLoption option,void * value)60 CURLcode CurlApi::EasySetOptPtr(CURL* curl, CURLoption option, void* value) {
61   CHECK(VerifyOptionType(option, CURLOPTTYPE_OBJECTPOINT))
62       << "Only options that expect a pointer data type must be specified here";
63   return curl_easy_setopt(curl, option, value);
64 }
65 
EasySetOptCallback(CURL * curl,CURLoption option,intptr_t address)66 CURLcode CurlApi::EasySetOptCallback(CURL* curl,
67                                      CURLoption option,
68                                      intptr_t address) {
69   CHECK(VerifyOptionType(option, CURLOPTTYPE_FUNCTIONPOINT))
70       << "Only options that expect a function pointers must be specified here";
71   return curl_easy_setopt(curl, option, address);
72 }
73 
EasySetOptOffT(CURL * curl,CURLoption option,curl_off_t value)74 CURLcode CurlApi::EasySetOptOffT(CURL* curl,
75                                  CURLoption option,
76                                  curl_off_t value) {
77   CHECK(VerifyOptionType(option, CURLOPTTYPE_OFF_T))
78       << "Only options that expect a large data size must be specified here";
79   return curl_easy_setopt(curl, option, value);
80 }
81 
EasyPerform(CURL * curl)82 CURLcode CurlApi::EasyPerform(CURL* curl) {
83   return curl_easy_perform(curl);
84 }
85 
EasyGetInfoInt(CURL * curl,CURLINFO info,int * value) const86 CURLcode CurlApi::EasyGetInfoInt(CURL* curl, CURLINFO info, int* value) const {
87   CHECK_EQ(CURLINFO_LONG, info & CURLINFO_TYPEMASK) << "Wrong option type";
88   long data = 0;  // NOLINT(runtime/int) - curl expects a long here.
89   CURLcode code = curl_easy_getinfo(curl, info, &data);
90   if (code == CURLE_OK)
91     *value = static_cast<int>(data);
92   return code;
93 }
94 
EasyGetInfoDbl(CURL * curl,CURLINFO info,double * value) const95 CURLcode CurlApi::EasyGetInfoDbl(CURL* curl,
96                                  CURLINFO info,
97                                  double* value) const {
98   CHECK_EQ(CURLINFO_DOUBLE, info & CURLINFO_TYPEMASK) << "Wrong option type";
99   return curl_easy_getinfo(curl, info, value);
100 }
101 
EasyGetInfoStr(CURL * curl,CURLINFO info,std::string * value) const102 CURLcode CurlApi::EasyGetInfoStr(CURL* curl,
103                                  CURLINFO info,
104                                  std::string* value) const {
105   CHECK_EQ(CURLINFO_STRING, info & CURLINFO_TYPEMASK) << "Wrong option type";
106   char* data = nullptr;
107   CURLcode code = curl_easy_getinfo(curl, info, &data);
108   if (code == CURLE_OK)
109     *value = data;
110   return code;
111 }
112 
EasyGetInfoPtr(CURL * curl,CURLINFO info,void ** value) const113 CURLcode CurlApi::EasyGetInfoPtr(CURL* curl,
114                                  CURLINFO info,
115                                  void** value) const {
116   // CURL uses "string" type for generic pointer info. Go figure.
117   CHECK_EQ(CURLINFO_STRING, info & CURLINFO_TYPEMASK) << "Wrong option type";
118   return curl_easy_getinfo(curl, info, value);
119 }
120 
EasyStrError(CURLcode code) const121 std::string CurlApi::EasyStrError(CURLcode code) const {
122   return curl_easy_strerror(code);
123 }
124 
MultiInit()125 CURLM* CurlApi::MultiInit() {
126   return curl_multi_init();
127 }
128 
MultiCleanup(CURLM * multi_handle)129 CURLMcode CurlApi::MultiCleanup(CURLM* multi_handle) {
130   return curl_multi_cleanup(multi_handle);
131 }
132 
MultiInfoRead(CURLM * multi_handle,int * msgs_in_queue)133 CURLMsg* CurlApi::MultiInfoRead(CURLM* multi_handle, int* msgs_in_queue) {
134   return curl_multi_info_read(multi_handle, msgs_in_queue);
135 }
136 
MultiAddHandle(CURLM * multi_handle,CURL * curl_handle)137 CURLMcode CurlApi::MultiAddHandle(CURLM* multi_handle, CURL* curl_handle) {
138   return curl_multi_add_handle(multi_handle, curl_handle);
139 }
140 
MultiRemoveHandle(CURLM * multi_handle,CURL * curl_handle)141 CURLMcode CurlApi::MultiRemoveHandle(CURLM* multi_handle, CURL* curl_handle) {
142   return curl_multi_remove_handle(multi_handle, curl_handle);
143 }
144 
MultiSetSocketCallback(CURLM * multi_handle,curl_socket_callback socket_callback,void * userp)145 CURLMcode CurlApi::MultiSetSocketCallback(CURLM* multi_handle,
146                                           curl_socket_callback socket_callback,
147                                           void* userp) {
148   CURLMcode code =
149       curl_multi_setopt(multi_handle, CURLMOPT_SOCKETFUNCTION, socket_callback);
150   if (code != CURLM_OK)
151     return code;
152   return curl_multi_setopt(multi_handle, CURLMOPT_SOCKETDATA, userp);
153 }
154 
MultiSetTimerCallback(CURLM * multi_handle,curl_multi_timer_callback timer_callback,void * userp)155 CURLMcode CurlApi::MultiSetTimerCallback(
156     CURLM* multi_handle,
157     curl_multi_timer_callback timer_callback,
158     void* userp) {
159   CURLMcode code =
160       curl_multi_setopt(multi_handle, CURLMOPT_TIMERFUNCTION, timer_callback);
161   if (code != CURLM_OK)
162     return code;
163   return curl_multi_setopt(multi_handle, CURLMOPT_TIMERDATA, userp);
164 }
165 
MultiAssign(CURLM * multi_handle,curl_socket_t sockfd,void * sockp)166 CURLMcode CurlApi::MultiAssign(CURLM* multi_handle,
167                                curl_socket_t sockfd,
168                                void* sockp) {
169   return curl_multi_assign(multi_handle, sockfd, sockp);
170 }
171 
MultiSocketAction(CURLM * multi_handle,curl_socket_t s,int ev_bitmask,int * running_handles)172 CURLMcode CurlApi::MultiSocketAction(CURLM* multi_handle,
173                                      curl_socket_t s,
174                                      int ev_bitmask,
175                                      int* running_handles) {
176   return curl_multi_socket_action(multi_handle, s, ev_bitmask, running_handles);
177 }
178 
MultiStrError(CURLMcode code) const179 std::string CurlApi::MultiStrError(CURLMcode code) const {
180   return curl_multi_strerror(code);
181 }
182 
183 }  // namespace http
184 }  // namespace brillo
185