1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "http_request.h"
17
18 #include <curl/curl.h>
19 #include <curl/easy.h>
20 #include <cinttypes>
21
22 #include "net_mgr_log_wrapper.h"
23
24 namespace OHOS {
25 namespace NetManagerStandard {
HttpRequest()26 HttpRequest::HttpRequest()
27 {
28 CURLcode errCode = curl_global_init(CURL_GLOBAL_ALL);
29 if (errCode != CURLE_OK) {
30 NETMGR_LOG_E("curl_global_init failed, errCode:[%{public}x]!", errCode);
31 }
32 }
33
~HttpRequest()34 HttpRequest::~HttpRequest()
35 {
36 curl_global_cleanup();
37 }
38
SetIfaceName(const std::string & ifaceName)39 void HttpRequest::SetIfaceName(const std::string &ifaceName)
40 {
41 const std::string ifPrefix("if!");
42 const auto preLength = ifPrefix.length();
43 if ((ifaceName.length() > preLength && ifaceName.substr(0, preLength) == ifPrefix) || ifaceName.empty()) {
44 ifaceName_ = ifaceName;
45 } else {
46 ifaceName_ = ifPrefix + ifaceName;
47 }
48 }
49
HttpGetHeader(const std::string & strUrl,std::string & strHeader)50 int32_t HttpRequest::HttpGetHeader(const std::string &strUrl, std::string &strHeader)
51 {
52 return HttpRequestHeaderExec(strUrl, strHeader);
53 }
54
HttpGet(const std::string & strUrl,std::string & strResponse)55 int32_t HttpRequest::HttpGet(const std::string &strUrl, std::string &strResponse)
56 {
57 NETMGR_LOG_I("Enter HttpGet");
58 return HttpRequestExec(HttpReqType::HTTP_REQUEST_TYPE_GET, strUrl, "", strResponse);
59 }
60
HttpPost(const std::string & strUrl,const std::string & strData,std::string & strResponse)61 int32_t HttpRequest::HttpPost(const std::string &strUrl, const std::string &strData, std::string &strResponse)
62 {
63 NETMGR_LOG_I("Enter HttpPost");
64 return HttpRequestExec(HttpReqType::HTTP_REQUEST_TYPE_POST, strUrl, strData, strResponse);
65 }
66
SetTransportTimeout(int64_t timeout)67 void HttpRequest::SetTransportTimeout(int64_t timeout)
68 {
69 NETMGR_LOG_I("Enter SetTransportTimeout");
70 if (timeout > 0) {
71 const double ratio = 0.75;
72 connectionTimeout_ = static_cast<int64_t>(timeout * ratio);
73 transOpTimeout_ = timeout;
74 NETMGR_LOG_D("TimeoutMs,connection:[%{public}" PRId64 "],transport:[%{public}" PRId64 "]!", connectionTimeout_,
75 transOpTimeout_);
76 }
77 }
78
GetLastTotalTime() const79 int64_t HttpRequest::GetLastTotalTime() const
80 {
81 NETMGR_LOG_I("Enter GetLastTotalTime");
82 return lastTransTime_;
83 }
84
operator ()(CURL * p) const85 void HttpRequest::CURLClean::operator()(CURL *p) const
86 {
87 if (p) {
88 curl_easy_cleanup(p);
89 }
90 }
91
HttpRequestExec(HttpReqType type,const std::string & strUrl,const std::string & strData,std::string & strResponse)92 int32_t HttpRequest::HttpRequestExec(
93 HttpReqType type, const std::string &strUrl, const std::string &strData, std::string &strResponse)
94 {
95 /* Check whether the URL is valid. */
96 if (strUrl.empty() || strUrl.length() > URL_SIZE) {
97 NETMGR_LOG_E("URL error!");
98 return -1;
99 }
100
101 std::unique_ptr<CURL, CURLClean> curl(curl_easy_init(), CURLClean());
102 if (curl.get() == nullptr) {
103 return -1;
104 }
105
106 int32_t rlt = SetCurlOpt(curl, type, strUrl, strData, strResponse);
107 if (rlt == 0) {
108 CURLcode errCode = CURLE_OK;
109 errCode = curl_easy_perform(curl.get());
110 rlt = static_cast<int32_t>(errCode);
111 }
112
113 return ParseExecResult(curl, rlt);
114 }
115
HttpRequestHeaderExec(const std::string & strUrl,std::string & strHeader)116 int32_t HttpRequest::HttpRequestHeaderExec(const std::string &strUrl, std::string &strHeader)
117 {
118 NETMGR_LOG_D("Enter HttpRequestHeaderExec, ifaceName:[%{public}s]", ifaceName_.c_str());
119 /* Check whether the URL is valid. */
120 if (strUrl.empty() || strUrl.length() > URL_SIZE) {
121 NETMGR_LOG_E("URL error!");
122 return -1;
123 }
124
125 std::unique_ptr<CURL, CURLClean> curl(curl_easy_init(), CURLClean());
126 if (curl.get() == nullptr) {
127 return -1;
128 }
129
130 int32_t rlt = SetCurlOptHeader(curl, strUrl, strHeader);
131 if (rlt == 0) {
132 CURLcode errCode = curl_easy_perform(curl.get());
133 errCode = (errCode == CURLE_OK || errCode == CURLE_WRITE_ERROR) ? CURLE_OK : errCode;
134 rlt = static_cast<int32_t>(errCode);
135 }
136
137 return ParseExecResult(curl, rlt);
138 }
139
ParseExecResult(const std::unique_ptr<CURL,CURLClean> & curl,int32_t rlt)140 int32_t HttpRequest::ParseExecResult(const std::unique_ptr<CURL, CURLClean> &curl, int32_t rlt)
141 {
142 CURLcode errCode = static_cast<CURLcode>(rlt);
143 if (errCode != CURLE_OK) {
144 NETMGR_LOG_E("HTTP request failed, errStr:[%{public}s]!", curl_easy_strerror(errCode));
145 return rlt;
146 }
147
148 lastTransTime_ = 0;
149 curl_off_t totalTimeUs = 0L;
150 errCode = curl_easy_getinfo(curl.get(), CURLINFO_TOTAL_TIME_T, &totalTimeUs);
151 if (errCode == CURLE_OK) {
152 lastTransTime_ = static_cast<int64_t>(totalTimeUs / 1000L);
153 NETMGR_LOG_D("HTTP request OK,total time in ms:[%{public}" PRId64 "]", lastTransTime_);
154 }
155 return static_cast<int32_t>(errCode);
156 }
157
SetCurlOpt(const std::unique_ptr<CURL,CURLClean> & curl,HttpReqType type,const std::string & strUrl,const std::string & strData,std::string & strResponse)158 int32_t HttpRequest::SetCurlOpt(const std::unique_ptr<CURL, CURLClean> &curl, HttpReqType type,
159 const std::string &strUrl, const std::string &strData, std::string &strResponse)
160 {
161 int32_t rlt = SetCurlOptCommon(curl, strUrl);
162 if (rlt != 0) {
163 return rlt;
164 }
165
166 /* receive the http header */
167 curl_easy_setopt(curl.get(), CURLOPT_HEADERFUNCTION, nullptr);
168 curl_easy_setopt(curl.get(), CURLOPT_HEADERDATA, nullptr);
169
170 /* receive the whole http response */
171 strResponse.clear();
172 curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, DataCallback);
173 curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &strResponse);
174
175 if (type == HttpReqType::HTTP_REQUEST_TYPE_POST) {
176 /* Specify post content */
177 curl_easy_setopt(curl.get(), CURLOPT_POST, 1L);
178 curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDSIZE, strData.length());
179 curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, strData.c_str());
180 }
181
182 return 0;
183 }
184
SetCurlOptHeader(const std::unique_ptr<CURL,CURLClean> & curl,const std::string & strUrl,std::string & strHeader)185 int32_t HttpRequest::SetCurlOptHeader(
186 const std::unique_ptr<CURL, CURLClean> &curl, const std::string &strUrl, std::string &strHeader)
187 {
188 int32_t rlt = SetCurlOptCommon(curl, strUrl);
189 if (rlt != 0) {
190 return rlt;
191 }
192
193 /* receive the http header */
194 strHeader.clear();
195 curl_easy_setopt(curl.get(), CURLOPT_HEADERFUNCTION, DataCallback);
196 curl_easy_setopt(curl.get(), CURLOPT_HEADERDATA, &strHeader);
197
198 /* not receive the whole http response */
199 curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, DataCallback);
200 curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, nullptr);
201 return 0;
202 }
203
SetCurlOptCommon(const std::unique_ptr<CURL,CURLClean> & curl,const std::string & strUrl)204 int32_t HttpRequest::SetCurlOptCommon(const std::unique_ptr<CURL, CURLClean> &curl, const std::string &strUrl)
205 {
206 /* Print request connection process and return http data on the screen */
207 curl_easy_setopt(curl.get(), CURLOPT_VERBOSE, 0L);
208
209 curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER, errorBuffer_);
210 /* not include the headers in the write callback */
211 curl_easy_setopt(curl.get(), CURLOPT_HEADER, 0L);
212 /* Specify url content */
213 curl_easy_setopt(curl.get(), CURLOPT_URL, strUrl.c_str());
214
215 /* https support */
216 /* the connection succeeds regardless of the peer certificate validation */
217 curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, 0L);
218 /* the connection succeeds regardless of the names in the certificate. */
219 curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, 0L);
220
221 curl_easy_setopt(curl.get(), CURLOPT_NOSIGNAL, 1L);
222
223 /* Allow redirect */
224 curl_easy_setopt(curl.get(), CURLOPT_FOLLOWLOCATION, 1L);
225 /* Set the maximum number of subsequent redirects */
226 curl_easy_setopt(curl.get(), CURLOPT_MAXREDIRS, 1L);
227
228 /* connection timeout time */
229 curl_easy_setopt(curl.get(), CURLOPT_CONNECTTIMEOUT_MS, connectionTimeout_);
230 /* transfer operation timeout time */
231 curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT_MS, transOpTimeout_);
232
233 CURLcode errCode = CURLE_OK;
234 if (!ifaceName_.empty()) {
235 errCode = curl_easy_setopt(curl.get(), CURLOPT_INTERFACE, ifaceName_.c_str());
236 if (errCode != CURLE_OK) {
237 NETMGR_LOG_E("CURLOPT_INTERFACE failed:%d!", errCode);
238 }
239 }
240 return static_cast<int32_t>(errCode);
241 }
242
DataCallback(char * data,size_t size,size_t nmemb,std::string * strBuffer)243 int32_t HttpRequest::DataCallback(char *data, size_t size, size_t nmemb, std::string *strBuffer)
244 {
245 if (strBuffer == nullptr || data == nullptr || size == 0) {
246 return 0;
247 }
248
249 int32_t writtenLen = static_cast<int32_t>(size * nmemb);
250 strBuffer->append(data, writtenLen);
251 return writtenLen;
252 }
253 } // namespace NetManagerStandard
254 } // namespace OHOS