• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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