1 /*
2 * Copyright (C) 2023 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 "net_http_probe.h"
17
18 #include <cerrno>
19 #include <memory>
20 #include <numeric>
21 #include <unistd.h>
22
23 #include "fwmark_client.h"
24 #include "netsys_controller.h"
25 #include "net_manager_constants.h"
26 #include "net_mgr_log_wrapper.h"
27 #include "net_proxy_userinfo.h"
28 #include "netmanager_base_common_utils.h"
29
30 #define NETPROBE_CURL_EASY_SET_OPTION(handle, opt, data) \
31 do { \
32 CURLcode result = curl_easy_setopt(handle, opt, data); \
33 if (result != CURLE_OK) { \
34 const char *err = curl_easy_strerror(result); \
35 NETMGR_LOG_E("Failed to set curl option: %{public}s, %{public}s %{public}d", #opt, err, result); \
36 return false; \
37 } \
38 } while (0)
39
40 namespace OHOS {
41 namespace NetManagerStandard {
42 namespace {
43 constexpr int PERFORM_POLL_INTERVAL_MS = 50;
44 constexpr int64_t HTTP_OK_CODE = 200;
45 constexpr int32_t DEFAULT_CONTENT_LENGTH_VALUE = -1;
46 constexpr int32_t MIN_VALID_CONTENT_LENGTH_VALUE = 5;
47 constexpr int32_t FAIL_CODE = 599;
48 constexpr int32_t PORTAL_CODE = 302;
49 constexpr int32_t HTTP_RES_CODE_BAD_REQUEST = 400;
50 constexpr int32_t HTTP_RES_CODE_CLIENT_ERRORS_MAX = 499;
51 constexpr int CURL_CONNECT_TIME_OUT_MS = 10000;
52 constexpr int CURL_OPERATE_TIME_OUT_MS = 10000;
53 constexpr int32_t DOMAIN_IP_ADDR_LEN_MAX = 128;
54 constexpr int32_t DEFAULT_HTTP_PORT = 80;
55 constexpr int32_t DEFAULT_HTTPS_PORT = 443;
56 constexpr const char *ADDR_SEPARATOR = ",";
57 constexpr const char *SYMBOL_COLON = ":";
58 const std::string DEFAULT_USER_AGENT = std::string("User-Agent: Mozilla/5.0 (X11; Linux x86_64) ") +
59 std::string("AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.32 Safari/537.36");
60 constexpr const char *CONNECTION_PROPERTY = "Connection: close";
61 constexpr const char *ACCEPT_ENCODING = "Accept-Encoding: gzip";
62 const std::string CONNECTION_CLOSE_VALUE = "close";
63 const std::string CONNECTION_KEY = "Connection:";
64 const std::string CONTENT_LENGTH_KEY = "Content-Length:";
65 const std::string KEY_WORDS_REDIRECTION = "location.replace";
66 const std::string HTML_TITLE_HTTP_EN = "http://";
67 const std::string HTML_TITLE_HTTPS_EN = "https://";
68 constexpr const char NEW_LINE_STR = '\n';
69 } // namespace
70
71 std::mutex NetHttpProbe::initCurlMutex_;
72 int32_t NetHttpProbe::useCurlCount_ = 0;
CurlGlobalInit()73 bool NetHttpProbe::CurlGlobalInit()
74 {
75 NETMGR_LOG_D("curl_global_init() in");
76 std::lock_guard<std::mutex> lock(initCurlMutex_);
77 if (useCurlCount_ == 0) {
78 NETMGR_LOG_D("Call curl_global_init()");
79 if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
80 NETMGR_LOG_E("curl_global_init() failed");
81 return false;
82 }
83 }
84 useCurlCount_++;
85 NETMGR_LOG_D("curl_global_init() count:[%{public}d]", useCurlCount_);
86 return true;
87 }
88
CurlGlobalCleanup()89 void NetHttpProbe::CurlGlobalCleanup()
90 {
91 NETMGR_LOG_D("CurlGlobalCleanup() in");
92 std::lock_guard<std::mutex> lock(initCurlMutex_);
93 useCurlCount_ = useCurlCount_ > 0 ? (useCurlCount_ - 1) : 0;
94 NETMGR_LOG_D("Curl global used count remain:[%{public}d]", useCurlCount_);
95 if (useCurlCount_ == 0) {
96 NETMGR_LOG_D("Call curl_global_cleanup()");
97 curl_global_cleanup();
98 }
99 }
100
NetHttpProbe(uint32_t netId,NetBearType bearType,const NetLinkInfo & netLinkInfo,ProbeType probeType)101 NetHttpProbe::NetHttpProbe(uint32_t netId, NetBearType bearType, const NetLinkInfo &netLinkInfo, ProbeType probeType)
102 : netId_(netId), netBearType_(bearType), netLinkInfo_(netLinkInfo), probeType_(probeType)
103 {
104 isCurlInit_ = NetHttpProbe::CurlGlobalInit();
105 }
106
~NetHttpProbe()107 NetHttpProbe::~NetHttpProbe()
108 {
109 NetHttpProbe::CurlGlobalCleanup();
110 isCurlInit_ = false;
111 }
112
SendProbe(ProbeType probeType,const std::string & httpUrl,const std::string & httpsUrl)113 int32_t NetHttpProbe::SendProbe(ProbeType probeType, const std::string &httpUrl, const std::string &httpsUrl)
114 {
115 NETMGR_LOG_I("Send net:[%{public}d] %{public}s probe in", netId_,
116 ((IsHttpsDetect(probeType)) ? "https" : "http"));
117 ClearProbeResult();
118 if (!CheckCurlGlobalInitState()) {
119 return NETMANAGER_ERR_INTERNAL;
120 }
121
122 if (!InitHttpCurl(probeType)) {
123 CleanHttpCurl();
124 return NETMANAGER_ERR_INTERNAL;
125 }
126
127 if (!SetCurlOptions(probeType, httpUrl, httpsUrl)) {
128 NETMGR_LOG_E("Set http/https probe options failed");
129 CleanHttpCurl();
130 return NETMANAGER_ERR_INTERNAL;
131 }
132
133 SendHttpProbeRequest();
134 RecvHttpProbeResponse();
135 CleanHttpCurl();
136 if (!defaultUseGlobalHttpProxy_) {
137 defaultUseGlobalHttpProxy_ = true;
138 }
139 return NETMANAGER_SUCCESS;
140 }
141
GetHttpProbeResult() const142 NetHttpProbeResult NetHttpProbe::GetHttpProbeResult() const
143 {
144 return httpProbeResult_;
145 }
146
GetHttpsProbeResult() const147 NetHttpProbeResult NetHttpProbe::GetHttpsProbeResult() const
148 {
149 return httpsProbeResult_;
150 }
151
UpdateNetLinkInfo(const NetLinkInfo & netLinkInfo)152 void NetHttpProbe::UpdateNetLinkInfo(const NetLinkInfo &netLinkInfo)
153 {
154 netLinkInfo_ = netLinkInfo;
155 }
156
UpdateGlobalHttpProxy(const HttpProxy & httpProxy)157 void NetHttpProbe::UpdateGlobalHttpProxy(const HttpProxy &httpProxy)
158 {
159 std::lock_guard<std::mutex> locker(proxyMtx_);
160 globalHttpProxy_ = httpProxy;
161 }
162
CheckCurlGlobalInitState()163 bool NetHttpProbe::CheckCurlGlobalInitState()
164 {
165 if (!isCurlInit_) {
166 NETMGR_LOG_E("Curl global does not initialized, attempting to reinitialize.");
167 isCurlInit_ = NetHttpProbe::CurlGlobalInit();
168 }
169 return isCurlInit_;
170 }
171
CleanHttpCurl()172 void NetHttpProbe::CleanHttpCurl()
173 {
174 if (httpCurl_) {
175 if (curlMulti_) {
176 curl_multi_remove_handle(curlMulti_, httpCurl_);
177 }
178 curl_easy_cleanup(httpCurl_);
179 httpCurl_ = nullptr;
180 }
181
182 if (httpsCurl_) {
183 if (curlMulti_) {
184 curl_multi_remove_handle(curlMulti_, httpsCurl_);
185 }
186 curl_easy_cleanup(httpsCurl_);
187 httpsCurl_ = nullptr;
188 }
189
190 if (httpResolveList_) {
191 curl_slist_free_all(httpResolveList_);
192 httpResolveList_ = nullptr;
193 }
194
195 if (httpsResolveList_) {
196 curl_slist_free_all(httpsResolveList_);
197 httpsResolveList_ = nullptr;
198 }
199
200 if (curlMulti_) {
201 curl_multi_cleanup(curlMulti_);
202 curlMulti_ = nullptr;
203 }
204 }
205
ClearProbeResult()206 void NetHttpProbe::ClearProbeResult()
207 {
208 httpProbeResult_ = {};
209 httpsProbeResult_ = {};
210 }
211
ExtractDomainFormUrl(const std::string & url)212 std::string NetHttpProbe::ExtractDomainFormUrl(const std::string &url)
213 {
214 if (url.empty()) {
215 return std::string();
216 }
217
218 size_t doubleSlashPos = url.find("//");
219 if (doubleSlashPos == std::string::npos) {
220 return url;
221 }
222
223 std::string domain;
224 size_t domainStartPos = doubleSlashPos + 2;
225 size_t domainEndPos = url.find('/', domainStartPos);
226 if (domainEndPos != std::string::npos) {
227 domain = url.substr(domainStartPos, domainEndPos - domainStartPos);
228 } else {
229 domain = url.substr(domainStartPos);
230 }
231 return domain;
232 }
233
GetAddrInfo(const std::string & domain)234 std::string NetHttpProbe::GetAddrInfo(const std::string &domain)
235 {
236 if (domain.empty()) {
237 NETMGR_LOG_E("domain is empty");
238 return std::string();
239 }
240
241 std::vector<AddrInfo> result;
242 AddrInfo hints = {};
243 std::string serverName;
244 if (NetsysController::GetInstance().GetAddrInfo(domain, serverName, hints, netId_, result) < 0) {
245 NETMGR_LOG_E("Get net[%{public}d] address info failed,errno[%{public}d]:%{public}s", netId_, errno,
246 strerror(errno));
247 return std::string();
248 }
249 if (result.empty()) {
250 NETMGR_LOG_E("Get net[%{public}d] address info return nullptr result", netId_);
251 return std::string();
252 }
253
254 std::string ipAddress;
255 char ip[DOMAIN_IP_ADDR_LEN_MAX] = {0};
256 for (auto &node : result) {
257 errno_t err = memset_s(&ip, sizeof(ip), 0, sizeof(ip));
258 if (err != EOK) {
259 NETMGR_LOG_E("memset_s failed,err:%{public}d", err);
260 return std::string();
261 }
262
263 if (node.aiFamily == AF_INET) {
264 if (!inet_ntop(AF_INET, &node.aiAddr.sin.sin_addr, ip, sizeof(ip))) {
265 continue;
266 }
267 } else if (node.aiFamily == AF_INET6) {
268 if (!inet_ntop(AF_INET6, &node.aiAddr.sin6.sin6_addr, ip, sizeof(ip))) {
269 continue;
270 }
271 }
272 if (ipAddress.find(ip) != std::string::npos) {
273 continue;
274 }
275 ipAddress = ipAddress.empty() ? (ipAddress + ip) : (ipAddress + ADDR_SEPARATOR + ip);
276 }
277 return ipAddress;
278 }
279
InitHttpCurl(ProbeType probeType)280 bool NetHttpProbe::InitHttpCurl(ProbeType probeType)
281 {
282 curlMulti_ = curl_multi_init();
283 if (curlMulti_ == nullptr) {
284 NETMGR_LOG_E("curl_multi_init() failed.");
285 return false;
286 }
287
288 if (IsHttpDetect(probeType)) {
289 httpCurl_ = curl_easy_init();
290 if (!httpCurl_) {
291 NETMGR_LOG_E("httpCurl_ init failed");
292 return false;
293 }
294 }
295
296 if (IsHttpsDetect(probeType)) {
297 httpsCurl_ = curl_easy_init();
298 if (!httpsCurl_) {
299 NETMGR_LOG_E("httpsCurl_ init failed");
300 return false;
301 }
302 }
303 return true;
304 }
305
SetCurlOptions(ProbeType probeType,const std::string & httpUrl,const std::string & httpsUrl)306 bool NetHttpProbe::SetCurlOptions(ProbeType probeType, const std::string &httpUrl, const std::string &httpsUrl)
307 {
308 bool useProxy = false;
309 if (!SetProxyOption(probeType, useProxy)) {
310 NETMGR_LOG_E("Set curl proxy option failed.");
311 return false;
312 }
313 if (!SendDnsProbe(probeType, httpUrl, httpsUrl, useProxy)) {
314 NETMGR_LOG_E("Set resolve option failed.");
315 return false;
316 }
317
318 if (IsHttpDetect(probeType)) {
319 if (!SetHttpOptions(ProbeType::PROBE_HTTP, httpCurl_, httpUrl)) {
320 return false;
321 }
322 }
323
324 if (IsHttpsDetect(probeType)) {
325 if (!SetHttpOptions(ProbeType::PROBE_HTTPS, httpsCurl_, httpsUrl)) {
326 return false;
327 }
328 }
329
330 return true;
331 }
332
HeaderCallback(char * buffer,size_t size,size_t nitems,void * userdata)333 size_t NetHttpProbe::HeaderCallback(char* buffer, size_t size, size_t nitems, void* userdata)
334 {
335 std::string* data = static_cast<std::string*>(userdata);
336 NETMGR_LOG_D("recv data size:[%{public}zu] nitems:[%{public}zu]", size, nitems);
337 if (size * nitems > CURL_MAX_HTTP_HEADER) {
338 NETMGR_LOG_E("recv data error, greater than 100K");
339 return 0;
340 }
341 if (data != nullptr && buffer != nullptr) {
342 data->append(buffer, size * nitems);
343 }
344 return size * nitems;
345 }
346
SetHttpOptions(ProbeType probeType,CURL * curl,const std::string & url)347 bool NetHttpProbe::SetHttpOptions(ProbeType probeType, CURL *curl, const std::string &url)
348 {
349 if (!curl) {
350 NETMGR_LOG_E("curl is nullptr");
351 return false;
352 }
353 if (url.empty()) {
354 NETMGR_LOG_E("Probe url is empty");
355 return false;
356 }
357 struct curl_slist *list = nullptr;
358 list = curl_slist_append(list, DEFAULT_USER_AGENT.c_str());
359 list = curl_slist_append(list, CONNECTION_PROPERTY);
360 list = curl_slist_append(list, ACCEPT_ENCODING);
361 if (!list) {
362 NETMGR_LOG_E("add request header properties failed.");
363 return false;
364 }
365
366 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_VERBOSE, 0L);
367 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_FORBID_REUSE, 1L);
368 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_URL, url.c_str());
369 if (IsHttpsDetect(probeType)) {
370 /* the connection succeeds regardless of the peer certificate validation */
371 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYPEER, 0L);
372 /* the connection succeeds regardless of the names in the certificate. */
373 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYHOST, 0L);
374 }
375 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_NOSIGNAL, 1L);
376 /* connection timeout time */
377 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_CONNECTTIMEOUT_MS, CURL_CONNECT_TIME_OUT_MS);
378 /* transfer operation timeout time */
379 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_TIMEOUT_MS, CURL_OPERATE_TIME_OUT_MS);
380 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_INTERFACE, netLinkInfo_.ifaceName_.c_str());
381 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_HEADERFUNCTION, NetHttpProbe::HeaderCallback);
382 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_HEADERDATA, &respHeader_);
383 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_HEADER, 1L);
384 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_HTTPHEADER, list);
385 NETPROBE_CURL_EASY_SET_OPTION(curl, CURLOPT_ERRORBUFFER, errBuffer);
386
387 CURLMcode code = curl_multi_add_handle(curlMulti_, curl);
388 if (code != CURLM_OK) {
389 NETMGR_LOG_E("curl multi add handle failed, code:[%{public}d]", code);
390 return false;
391 }
392 return true;
393 }
394
SetProxyOption(ProbeType probeType,bool & useHttpProxy)395 bool NetHttpProbe::SetProxyOption(ProbeType probeType, bool &useHttpProxy)
396 {
397 useHttpProxy = false;
398 /* WIFI or Ethernet require the use of proxy for network detection */
399 if (netBearType_ != BEARER_WIFI && netBearType_ != BEARER_ETHERNET) {
400 NETMGR_LOG_W("Net:[%{public}d] bear type:[%{public}d], no proxy probe required.", netId_, probeType);
401 return true;
402 }
403
404 std::string proxyHost;
405 int32_t proxyPort = 0;
406 /* Prioritize the use of global HTTP proxy, if there is no global proxy, use network http proxy */
407 if (!LoadProxy(proxyHost, proxyPort)) {
408 NETMGR_LOG_D("global http proxy or network proxy is empty.");
409 return true;
410 }
411
412 std::string proxyDomain = ExtractDomainFormUrl(proxyHost);
413 if (proxyDomain.empty()) {
414 NETMGR_LOG_E("Extract proxy domain from host return empty.");
415 return true;
416 }
417 std::string proxyIpAddress = GetAddrInfo(proxyDomain);
418
419 NETMGR_LOG_I("Using proxy for http probe on netId:[%{public}d]", netId_);
420 bool ret = true;
421 if (IsHttpDetect(probeType)) {
422 if (!SetProxyInfo(httpCurl_, proxyHost, proxyPort)) {
423 NETMGR_LOG_E("Set proxy info failed.");
424 }
425 ret &= SetResolveOption(ProbeType::PROBE_HTTP, proxyDomain, proxyIpAddress, proxyPort);
426 }
427
428 if (IsHttpsDetect(probeType)) {
429 if (!SetProxyInfo(httpsCurl_, proxyHost, proxyPort)) {
430 NETMGR_LOG_E("Set proxy info failed.");
431 }
432 ret &= SetResolveOption(ProbeType::PROBE_HTTPS, proxyDomain, proxyIpAddress, proxyPort);
433 }
434 useHttpProxy = true;
435 return ret;
436 }
437
SetProxyInfo(CURL * curlHandler,const std::string & proxyHost,int32_t proxyPort)438 bool NetHttpProbe::SetProxyInfo(CURL *curlHandler, const std::string &proxyHost, int32_t proxyPort)
439 {
440 auto proxyType = (proxyHost.find("https://") != std::string::npos) ? CURLPROXY_HTTPS : CURLPROXY_HTTP;
441 if (curlHandler == nullptr) {
442 NETMGR_LOG_E("curlHandler is nullptr.");
443 return false;
444 }
445 NETPROBE_CURL_EASY_SET_OPTION(curlHandler, CURLOPT_PROXY, proxyHost.c_str());
446 NETPROBE_CURL_EASY_SET_OPTION(curlHandler, CURLOPT_PROXYPORT, proxyPort);
447 NETPROBE_CURL_EASY_SET_OPTION(curlHandler, CURLOPT_PROXYTYPE, proxyType);
448 NETPROBE_CURL_EASY_SET_OPTION(curlHandler, CURLOPT_HTTPPROXYTUNNEL, 1L);
449 if (!SetUserInfo(curlHandler)) {
450 NETMGR_LOG_E("Set user info failed.");
451 }
452 return true;
453 }
454
SetUserInfo(CURL * curlHandler)455 bool NetHttpProbe::SetUserInfo(CURL *curlHandler)
456 {
457 HttpProxy tempProxy;
458 auto userInfoHelp = NetProxyUserinfo::GetInstance();
459 userInfoHelp.GetHttpProxyHostPass(tempProxy);
460 auto username = tempProxy.GetUsername();
461 auto passwd = tempProxy.GetPassword();
462 if (!username.empty()) {
463 NETPROBE_CURL_EASY_SET_OPTION(curlHandler, CURLOPT_PROXYUSERNAME, username.c_str());
464 NETPROBE_CURL_EASY_SET_OPTION(curlHandler, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
465 if (!passwd.empty()) {
466 NETPROBE_CURL_EASY_SET_OPTION(curlHandler, CURLOPT_PROXYPASSWORD, passwd.c_str());
467 }
468 }
469 return true;
470 }
471
SetResolveOption(ProbeType probeType,const std::string & domain,const std::string & ipAddress,int32_t port)472 bool NetHttpProbe::SetResolveOption(ProbeType probeType, const std::string &domain, const std::string &ipAddress,
473 int32_t port)
474 {
475 if (domain.empty()) {
476 NETMGR_LOG_E("domain is empty");
477 return false;
478 }
479
480 if (ipAddress.empty()) {
481 NETMGR_LOG_E("ipAddress is empty");
482 return false;
483 }
484
485 std::string resolve = domain + SYMBOL_COLON + std::to_string(port) + SYMBOL_COLON + ipAddress;
486 if (IsHttpDetect(probeType)) {
487 httpResolveList_ = curl_slist_append(httpResolveList_, resolve.c_str());
488 NETPROBE_CURL_EASY_SET_OPTION(httpCurl_, CURLOPT_RESOLVE, httpResolveList_);
489 }
490
491 if (IsHttpsDetect(probeType)) {
492 httpsResolveList_ = curl_slist_append(httpsResolveList_, resolve.c_str());
493 NETPROBE_CURL_EASY_SET_OPTION(httpsCurl_, CURLOPT_RESOLVE, httpsResolveList_);
494 }
495 return true;
496 }
497
SendDnsProbe(ProbeType probeType,const std::string & httpUrl,const std::string & httpsUrl,const bool useProxy)498 bool NetHttpProbe::SendDnsProbe(ProbeType probeType, const std::string &httpUrl, const std::string &httpsUrl,
499 const bool useProxy)
500 {
501 if (useProxy) {
502 NETMGR_LOG_W("Net[%{public}d] probe use http proxy,no DNS detection required.", netId_);
503 return true;
504 }
505
506 std::string httpDomain;
507 std::string httpsDomain;
508 if (IsHttpDetect(probeType)) {
509 httpDomain = ExtractDomainFormUrl(httpUrl);
510 if (httpDomain.empty()) {
511 NETMGR_LOG_E("The http domain extracted from [%{public}s] is empty", httpUrl.c_str());
512 return false;
513 }
514 }
515
516 if (IsHttpsDetect(probeType)) {
517 httpsDomain = ExtractDomainFormUrl(httpsUrl);
518 if (httpsDomain.empty()) {
519 NETMGR_LOG_E("The https domain extracted from [%{public}s] is empty", httpsUrl.c_str());
520 return false;
521 }
522 }
523
524 std::string ipAddress;
525 if (httpDomain == httpsDomain) {
526 NETMGR_LOG_I("Get net[%{public}d] ip addr for HTTP&HTTPS probe url ", netId_);
527 ipAddress = GetAddrInfo(httpDomain);
528 return SetResolveOption(ProbeType::PROBE_HTTP, httpDomain, ipAddress, DEFAULT_HTTP_PORT) &&
529 SetResolveOption(ProbeType::PROBE_HTTPS, httpsDomain, ipAddress, DEFAULT_HTTPS_PORT);
530 }
531
532 if (IsHttpDetect(probeType)) {
533 NETMGR_LOG_I("Get net[%{public}d] ip addr for HTTP probe url ", netId_);
534 ipAddress = GetAddrInfo(httpDomain);
535 return SetResolveOption(ProbeType::PROBE_HTTP, httpDomain, ipAddress, DEFAULT_HTTP_PORT);
536 }
537
538 if (IsHttpsDetect(probeType)) {
539 NETMGR_LOG_I("Get net[%{public}d] ip addr for HTTPS probe url ", netId_);
540 ipAddress = GetAddrInfo(httpsDomain);
541 return SetResolveOption(ProbeType::PROBE_HTTPS, httpsDomain, ipAddress, DEFAULT_HTTPS_PORT);
542 }
543 return false;
544 }
545
SendHttpProbeRequest()546 void NetHttpProbe::SendHttpProbeRequest()
547 {
548 if (!curlMulti_) {
549 NETMGR_LOG_E("curlMulti_ is nullptr");
550 return;
551 }
552
553 int running = 0;
554 do {
555 CURLMcode result = curl_multi_perform(curlMulti_, &running);
556 if ((result == CURLM_OK) && running) {
557 result = curl_multi_poll(curlMulti_, nullptr, 0, PERFORM_POLL_INTERVAL_MS, nullptr);
558 }
559 if (result != CURLM_OK) {
560 NETMGR_LOG_E("curl_multi_perform() error, error code:[%{public}d]", result);
561 break;
562 }
563 } while (running);
564 }
565
GetHeaderField(std::string key)566 std::string NetHttpProbe::GetHeaderField(std::string key)
567 {
568 std::string result = "";
569 if (respHeader_.empty()) {
570 NETMGR_LOG_I("net[%{public}d], probeType[%{public}d] response header empty", netId_, probeType_);
571 return result;
572 }
573 size_t start = respHeader_.find(key);
574 if (start != std::string::npos) {
575 start += key.length();
576 size_t end = respHeader_.find(NEW_LINE_STR, start);
577 result = respHeader_.substr(start, end - start);
578 result = CommonUtils::Trim(result);
579 }
580 NETMGR_LOG_I("net[%{public}d], probeType[%{public}d], key:[%{public}s]", netId_, probeType_, key.c_str());
581 return result;
582 }
583
CheckRespCode(int64_t respCode)584 int64_t NetHttpProbe::CheckRespCode(int64_t respCode)
585 {
586 NETMGR_LOG_D("net[%{public}d], response code before check:%{public}" PRId64, netId_, respCode);
587 if (respCode == HTTP_OK_CODE) {
588 std::string contentLengthValue = GetHeaderField(CONTENT_LENGTH_KEY);
589 int32_t lengthValue = contentLengthValue.empty() ? DEFAULT_CONTENT_LENGTH_VALUE :
590 CommonUtils::StrToInt(contentLengthValue, DEFAULT_CONTENT_LENGTH_VALUE);
591 if (lengthValue == DEFAULT_CONTENT_LENGTH_VALUE) {
592 if (respHeader_.empty()) {
593 NETMGR_LOG_I("net[%{public}d], response code 200 with content length -1, consider as fail", netId_);
594 return FAIL_CODE;
595 }
596 } else if (lengthValue < MIN_VALID_CONTENT_LENGTH_VALUE) {
597 NETMGR_LOG_I("net[%{public}d], response code 200, content length less 5, consider as fail", netId_);
598 return FAIL_CODE;
599 }
600
601 std::string value = GetHeaderField(CONNECTION_KEY);
602 value = CommonUtils::ToLower(value);
603 if (CONNECTION_CLOSE_VALUE.compare(value) == 0 &&
604 probeType_ == ProbeType::PROBE_HTTP) {
605 NETMGR_LOG_I("net[%{public}d] http detection, response code 200 with connection close, consider as fail",
606 netId_);
607 return FAIL_CODE;
608 }
609 }
610 int64_t result = respCode;
611 if (IsHttpDetect(probeType_)) {
612 result = CheckClientErrorRespCode(result);
613 }
614 return result;
615 }
616
CheckClientErrorRespCode(int64_t respCode)617 int64_t NetHttpProbe::CheckClientErrorRespCode(int64_t respCode)
618 {
619 int64_t result = respCode;
620 if (respCode >= HTTP_RES_CODE_BAD_REQUEST && respCode <= HTTP_RES_CODE_CLIENT_ERRORS_MAX) {
621 std::string errMsg(errBuffer);
622 if ((errMsg.find(HTML_TITLE_HTTP_EN) != std::string::npos ||
623 errMsg.find(HTML_TITLE_HTTPS_EN) != std::string::npos) &&
624 errMsg.find(KEY_WORDS_REDIRECTION) != std::string::npos) {
625 NETMGR_LOG_I("net[%{public}d] reset url in content, consider as portal when http return %{public}" PRId64,
626 netId_, respCode);
627 result = PORTAL_CODE;
628 }
629 }
630 return result;
631 }
632
RecvHttpProbeResponse()633 void NetHttpProbe::RecvHttpProbeResponse()
634 {
635 if (!curlMulti_) {
636 NETMGR_LOG_E("curlMulti_ is nullptr");
637 return;
638 }
639 CURLMsg *curlMsg = nullptr;
640 int32_t msgQueue = 0;
641 while ((curlMsg = curl_multi_info_read(curlMulti_, &msgQueue)) != nullptr) {
642 if (curlMsg->msg != CURLMSG_DONE) {
643 NETMGR_LOG_W("curl multi read not done, msg:[%{public}d]", curlMsg->msg);
644 continue;
645 }
646
647 if (!curlMsg->easy_handle) {
648 NETMGR_LOG_E("Read nullptr curl easy handle");
649 continue;
650 }
651
652 int64_t responseCode = 0;
653 curl_easy_getinfo(curlMsg->easy_handle, CURLINFO_RESPONSE_CODE, &responseCode);
654 responseCode = CheckRespCode(responseCode);
655 std::string redirectUrl;
656 char* url = nullptr;
657 curl_easy_getinfo(curlMsg->easy_handle, CURLINFO_REDIRECT_URL, &url);
658 if (url != nullptr) {
659 redirectUrl = url;
660 } else {
661 curl_easy_getinfo(curlMsg->easy_handle, CURLINFO_EFFECTIVE_URL, &url);
662 redirectUrl = url;
663 }
664
665 if (curlMsg->easy_handle == httpCurl_) {
666 httpProbeResult_ = {responseCode, redirectUrl};
667 NETMGR_LOG_I("Recv net[%{public}d] http probe response, code:[%{public}d]", netId_,
668 httpProbeResult_.GetCode());
669 } else if (curlMsg->easy_handle == httpsCurl_) {
670 httpsProbeResult_ = {responseCode, redirectUrl};
671 NETMGR_LOG_I("Recv net[%{public}d] https probe response, code:[%{public}d]", netId_,
672 httpsProbeResult_.GetCode());
673 } else {
674 NETMGR_LOG_E("Unknown curl handle.");
675 }
676 }
677 }
678
LoadProxy(std::string & proxyHost,int32_t & proxyPort)679 int32_t NetHttpProbe::LoadProxy(std::string &proxyHost, int32_t &proxyPort)
680 {
681 std::lock_guard<std::mutex> locker(proxyMtx_);
682 if (!globalHttpProxy_.GetHost().empty() && defaultUseGlobalHttpProxy_) {
683 proxyHost = globalHttpProxy_.GetHost();
684 proxyPort = static_cast<int32_t>(globalHttpProxy_.GetPort());
685 } else if (!netLinkInfo_.httpProxy_.GetHost().empty()) {
686 proxyHost = netLinkInfo_.httpProxy_.GetHost();
687 proxyPort = static_cast<int32_t>(netLinkInfo_.httpProxy_.GetPort());
688 } else {
689 return false;
690 }
691 return true;
692 }
693
ProbeWithoutGlobalHttpProxy()694 void NetHttpProbe::ProbeWithoutGlobalHttpProxy()
695 {
696 defaultUseGlobalHttpProxy_ = false;
697 }
698
IsHttpDetect(ProbeType probeType)699 bool NetHttpProbe::IsHttpDetect(ProbeType probeType)
700 {
701 return probeType == ProbeType::PROBE_HTTP || probeType == ProbeType::PROBE_HTTP_FALLBACK;
702 }
703
IsHttpsDetect(ProbeType probeType)704 bool NetHttpProbe::IsHttpsDetect(ProbeType probeType)
705 {
706 return probeType == ProbeType::PROBE_HTTPS || probeType == ProbeType::PROBE_HTTPS_FALLBACK;
707 }
708
709 } // namespace NetManagerStandard
710 } // namespace OHOS
711