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