• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2024 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 <iostream>
17 #include <memory>
18 
19 #include "http_client_task.h"
20 #include "http_client.h"
21 #include "http_client_constant.h"
22 #include "http_client_time.h"
23 #include "netstack_common_utils.h"
24 #include "netstack_log.h"
25 #include "net_conn_client.h"
26 
27 #define NETSTACK_CURL_EASY_SET_OPTION(handle, opt, data)                                                 \
28     do {                                                                                                 \
29         CURLcode result = curl_easy_setopt(handle, opt, data);                                           \
30         if (result != CURLE_OK) {                                                                        \
31             const char *err = curl_easy_strerror(result);                                                \
32             error_.SetCURLResult(result);                                                                \
33             NETSTACK_LOGE("Failed to set option: %{public}s, %{public}s %{public}d", #opt, err, result); \
34             return false;                                                                                \
35         }                                                                                                \
36     } while (0)
37 
38 namespace OHOS {
39 namespace NetStack {
40 namespace HttpClient {
41 
42 static constexpr size_t MAX_LIMIT = 100 * 1024 * 1024;
43 std::atomic<uint32_t> HttpClientTask::nextTaskId_(0);
44 
CheckFilePath(const std::string & fileName,std::string & realPath)45 bool CheckFilePath(const std::string &fileName, std::string &realPath)
46 {
47     char tmpPath[PATH_MAX] = {0};
48     if (!realpath(static_cast<const char *>(fileName.c_str()), tmpPath)) {
49         NETSTACK_LOGE("file name is error");
50         return false;
51     }
52 
53     realPath = tmpPath;
54     return true;
55 }
56 
HttpClientTask(const HttpClientRequest & request)57 HttpClientTask::HttpClientTask(const HttpClientRequest &request)
58     : request_(request),
59       type_(DEFAULT),
60       status_(IDLE),
61       taskId_(nextTaskId_++),
62       curlHeaderList_(nullptr),
63       canceled_(false),
64       file_(nullptr)
65 {
66     NETSTACK_LOGI("taskId_=%{public}d", taskId_);
67 
68     curlHandle_ = curl_easy_init();
69     if (!curlHandle_) {
70         NETSTACK_LOGE("Failed to create task!");
71         return;
72     }
73 
74     SetCurlOptions();
75 }
76 
HttpClientTask(const HttpClientRequest & request,TaskType type,const std::string & filePath)77 HttpClientTask::HttpClientTask(const HttpClientRequest &request, TaskType type, const std::string &filePath)
78     : request_(request),
79       type_(type),
80       status_(IDLE),
81       taskId_(nextTaskId_++),
82       curlHeaderList_(nullptr),
83       canceled_(false),
84       filePath_(filePath),
85       file_(nullptr)
86 {
87     NETSTACK_LOGI(
88         "taskId_=%{public}d type=%{public}d filePath=%{public}s",
89         taskId_, type_, filePath_.c_str());
90 
91     curlHandle_ = curl_easy_init();
92     if (!curlHandle_) {
93         NETSTACK_LOGE("Failed to create task!");
94         return;
95     }
96 
97     SetCurlOptions();
98 }
99 
~HttpClientTask()100 HttpClientTask::~HttpClientTask()
101 {
102     NETSTACK_LOGD("Destroy: taskId_=%{public}d", taskId_);
103     if (curlHeaderList_ != nullptr) {
104         curl_slist_free_all(curlHeaderList_);
105         curlHeaderList_ = nullptr;
106     }
107 
108     if (curlHandle_) {
109         curl_easy_cleanup(curlHandle_);
110         curlHandle_ = nullptr;
111     }
112 
113     if (file_ != nullptr) {
114         fclose(file_);
115         file_ = nullptr;
116     }
117 }
118 
GetHttpVersion(HttpProtocol ptcl) const119 uint32_t HttpClientTask::GetHttpVersion(HttpProtocol ptcl) const
120 {
121     if (ptcl == HttpProtocol::HTTP1_1) {
122         NETSTACK_LOGD("CURL_HTTP_VERSION_1_1");
123         return CURL_HTTP_VERSION_1_1;
124     } else if (ptcl == HttpProtocol::HTTP2) {
125         NETSTACK_LOGD("CURL_HTTP_VERSION_2_0");
126         return CURL_HTTP_VERSION_2_0;
127     } else if (ptcl == HttpProtocol::HTTP3) {
128         NETSTACK_LOGD("CURL_HTTP_VERSION_3");
129         return CURL_HTTP_VERSION_3;
130     }
131     return CURL_HTTP_VERSION_NONE;
132 }
133 
GetHttpProxyInfo(std::string & host,int32_t & port,std::string & exclusions,bool & tunnel)134 void HttpClientTask::GetHttpProxyInfo(std::string &host, int32_t &port, std::string &exclusions,
135                                       bool &tunnel)
136 {
137     if (request_.GetHttpProxyType() == HttpProxyType::USE_SPECIFIED) {
138         HttpProxy proxy = request_.GetHttpProxy();
139         host = proxy.host;
140         port = proxy.port;
141         exclusions = proxy.exclusions;
142         tunnel = proxy.tunnel;
143     } else {
144         using namespace NetManagerStandard;
145         NetManagerStandard::HttpProxy httpProxy;
146         NetConnClient::GetInstance().GetDefaultHttpProxy(httpProxy);
147         host = httpProxy.GetHost();
148         port = httpProxy.GetPort();
149         exclusions = CommonUtils::ToString(httpProxy.GetExclusionList());
150     }
151 }
152 
SetOtherCurlOption(CURL * handle)153 bool HttpClientTask::SetOtherCurlOption(CURL *handle)
154 {
155     // set proxy
156     std::string host;
157     std::string exclusions;
158     int32_t port = 0;
159     bool tunnel = false;
160     std::string url = request_.GetURL();
161     GetHttpProxyInfo(host, port, exclusions, tunnel);
162     if (!host.empty() && !CommonUtils::IsHostNameExcluded(url, exclusions, ",")) {
163         NETSTACK_LOGD("Set CURLOPT_PROXY: %{public}s:%{public}d, %{public}s", host.c_str(), port, exclusions.c_str());
164         NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_PROXY, host.c_str());
165         NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_PROXYPORT, port);
166         auto curlTunnelValue = (url.find("https://") != std::string::npos) ? 1L : 0L;
167         NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_HTTPPROXYTUNNEL, curlTunnelValue);
168         auto proxyType = (host.find("https://") != std::string::npos) ? CURLPROXY_HTTPS : CURLPROXY_HTTP;
169         NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_PROXYTYPE, proxyType);
170     }
171 
172 #ifdef NO_SSL_CERTIFICATION
173     // in real life, you should buy a ssl certification and rename it to /etc/ssl/cert.pem
174     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_SSL_VERIFYHOST, 0L);
175     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_SSL_VERIFYPEER, 0L);
176 #else
177 #ifndef WINDOWS_PLATFORM
178     NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_CAINFO, request_.GetCaPath().c_str());
179     NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_CAPATH, HttpConstant::HTTP_PREPARE_CA_PATH);
180 #endif // WINDOWS_PLATFORM
181     SetServerSSLCertOption(handle);
182 #endif // NO_SSL_CERTIFICATION
183 
184 #ifdef HTTP_CURL_PRINT_VERBOSE
185     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_VERBOSE, 1L);
186 #endif
187 
188 #ifndef WINDOWS_PLATFORM
189     NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_ACCEPT_ENCODING, "");
190 #endif
191 
192     return true;
193 }
194 
SetServerSSLCertOption(CURL * curl)195 bool HttpClientTask::SetServerSSLCertOption(CURL *curl)
196 {
197     std::string pins;
198     auto hostname = CommonUtils::GetHostnameFromURL(request_.GetURL());
199     auto ret = NetManagerStandard::NetConnClient::GetInstance().GetPinSetForHostName(hostname, pins);
200     if (ret != 0 || pins.empty()) {
201         NETSTACK_LOGD("Get no pin set by host name[%{public}s]", hostname.c_str());
202     } else {
203         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_PINNEDPUBLICKEY, pins.c_str());
204     }
205 
206     return true;
207 }
208 
SetUploadOptions(CURL * handle)209 bool HttpClientTask::SetUploadOptions(CURL *handle)
210 {
211     if (filePath_.empty()) {
212         NETSTACK_LOGE("HttpClientTask::SetUploadOptions() filePath_ is empty");
213         error_.SetErrorCode(HttpErrorCode::HTTP_UPLOAD_FAILED);
214         return false;
215     }
216 
217     std::string realPath;
218     if (!CheckFilePath(filePath_, realPath)) {
219         NETSTACK_LOGE("filePath_ does not exist! ");
220         error_.SetErrorCode(HttpErrorCode::HTTP_UPLOAD_FAILED);
221         return false;
222     }
223 
224     file_ = fopen(realPath.c_str(), "rb");
225     if (file_ == nullptr) {
226         NETSTACK_LOGE("HttpClientTask::SetUploadOptions() Failed to open file %{public}s", realPath.c_str());
227         error_.SetErrorCode(HttpErrorCode::HTTP_UPLOAD_FAILED);
228         return false;
229     }
230 
231     NETSTACK_LOGD("filePath_=%{public}s", realPath.c_str());
232     fseek(file_, 0, SEEK_END);
233     long size = ftell(file_);
234     rewind(file_);
235 
236     // Set the file data and file size to upload
237     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_READDATA, file_);
238     NETSTACK_LOGD("CURLOPT_INFILESIZE=%{public}ld", size);
239     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_INFILESIZE, size);
240     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_UPLOAD, 1L);
241 
242     return true;
243 }
244 
SetCurlOptions()245 bool HttpClientTask::SetCurlOptions()
246 {
247     auto method = request_.GetMethod();
248     if (method == HttpConstant::HTTP_METHOD_HEAD) {
249         NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_NOBODY, 1L);
250     }
251 
252     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_URL, request_.GetURL().c_str());
253 
254     if (type_ == TaskType::UPLOAD) {
255         if (!SetUploadOptions(curlHandle_)) {
256             return false;
257         }
258     } else {
259         NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_CUSTOMREQUEST, request_.GetMethod().c_str());
260 
261         if ((method == HttpConstant::HTTP_METHOD_POST || method == HttpConstant::HTTP_METHOD_PUT) &&
262             !request_.GetBody().empty()) {
263             NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_POST, 1L);
264             NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_POSTFIELDS, request_.GetBody().c_str());
265             NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_POSTFIELDSIZE, request_.GetBody().size());
266         }
267     }
268 
269     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_XFERINFOFUNCTION, ProgressCallback);
270     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_XFERINFODATA, &taskId_);
271     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_NOPROGRESS, 0L);
272 
273     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_WRITEFUNCTION, DataReceiveCallback);
274     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_WRITEDATA, &taskId_);
275 
276     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_HEADERFUNCTION, HeaderReceiveCallback);
277     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_HEADERDATA, &taskId_);
278 
279     if (curlHeaderList_ != nullptr) {
280         curl_slist_free_all(curlHeaderList_);
281         curlHeaderList_ = nullptr;
282     }
283     for (const auto &header : request_.GetHeaders()) {
284         std::string headerStr = header.first + HttpConstant::HTTP_HEADER_SEPARATOR + header.second;
285         curlHeaderList_ = curl_slist_append(curlHeaderList_, headerStr.c_str());
286     }
287     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_HTTPHEADER, curlHeaderList_);
288 
289     // Some servers don't like requests that are made without a user-agent field, so we provide one
290     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_USERAGENT, HttpConstant::HTTP_DEFAULT_USER_AGENT);
291 
292     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_FOLLOWLOCATION, 1L);
293 
294     /* first #undef CURL_DISABLE_COOKIES in curl config */
295     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_COOKIEFILE, "");
296 
297     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_NOSIGNAL, 1L);
298 
299     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_TIMEOUT_MS, request_.GetTimeout());
300     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_CONNECTTIMEOUT_MS, request_.GetConnectTimeout());
301 
302     NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_HTTP_VERSION, GetHttpVersion(request_.GetHttpProtocol()));
303 
304     if (!SetOtherCurlOption(curlHandle_)) {
305         return false;
306     }
307 
308     return true;
309 }
310 
Start()311 bool HttpClientTask::Start()
312 {
313     auto task = shared_from_this();
314     if (task->GetStatus() != TaskStatus::IDLE) {
315         NETSTACK_LOGD("task is running, taskId_=%{public}d", task->GetTaskId());
316         return false;
317     }
318 
319     if (!CommonUtils::HasInternetPermission()) {
320         NETSTACK_LOGE("Don't Has Internet Permission()");
321         error_.SetErrorCode(HttpErrorCode::HTTP_PERMISSION_DENIED_CODE);
322         return false;
323     }
324 
325     if (error_.GetErrorCode() != HttpErrorCode::HTTP_NONE_ERR) {
326         NETSTACK_LOGE("error_.GetErrorCode()=%{public}d", error_.GetErrorCode());
327         return false;
328     }
329 
330     request_.SetRequestTime(HttpTime::GetNowTimeGMT());
331 
332     HttpSession &session = HttpSession::GetInstance();
333     NETSTACK_LOGD("taskId_=%{public}d", taskId_);
334     task->canceled_ = false;
335 
336     response_.SetRequestTime(HttpTime::GetNowTimeGMT());
337     session.StartTask(task);
338 
339     return true;
340 }
341 
Cancel()342 void HttpClientTask::Cancel()
343 {
344     canceled_ = true;
345 }
346 
SetStatus(TaskStatus status)347 void HttpClientTask::SetStatus(TaskStatus status)
348 {
349     status_ = status;
350 }
351 
GetStatus()352 TaskStatus HttpClientTask::GetStatus()
353 {
354     return status_;
355 }
356 
GetType()357 TaskType HttpClientTask::GetType()
358 {
359     return type_;
360 }
361 
GetFilePath()362 const std::string &HttpClientTask::GetFilePath()
363 {
364     return filePath_;
365 }
366 
GetTaskId()367 unsigned int HttpClientTask::GetTaskId()
368 {
369     return taskId_;
370 }
371 
OnSuccess(const std::function<void (const HttpClientRequest & request,const HttpClientResponse & response)> & onSucceeded)372 void HttpClientTask::OnSuccess(
373     const std::function<void(const HttpClientRequest &request, const HttpClientResponse &response)> &onSucceeded)
374 {
375     onSucceeded_ = onSucceeded;
376 }
377 
OnCancel(const std::function<void (const HttpClientRequest & request,const HttpClientResponse & response)> & onCanceled)378 void HttpClientTask::OnCancel(
379     const std::function<void(const HttpClientRequest &request, const HttpClientResponse &response)> &onCanceled)
380 {
381     onCanceled_ = onCanceled;
382 }
383 
OnFail(const std::function<void (const HttpClientRequest & request,const HttpClientResponse & response,const HttpClientError & error)> & onFailed)384 void HttpClientTask::OnFail(
385     const std::function<void(const HttpClientRequest &request, const HttpClientResponse &response,
386                              const HttpClientError &error)> &onFailed)
387 {
388     onFailed_ = onFailed;
389 }
390 
OnDataReceive(const std::function<void (const HttpClientRequest & request,const uint8_t * data,size_t length)> & onDataReceive)391 void HttpClientTask::OnDataReceive(
392     const std::function<void(const HttpClientRequest &request, const uint8_t *data, size_t length)> &onDataReceive)
393 {
394     onDataReceive_ = onDataReceive;
395 }
396 
OnProgress(const std::function<void (const HttpClientRequest & request,u_long dlTotal,u_long dlNow,u_long ulTotal,u_long ulNow)> & onProgress)397 void HttpClientTask::OnProgress(const std::function<void(const HttpClientRequest &request, u_long dlTotal, u_long dlNow,
398                                                          u_long ulTotal, u_long ulNow)> &onProgress)
399 {
400     onProgress_ = onProgress;
401 }
402 
DataReceiveCallback(const void * data,size_t size,size_t memBytes,void * userData)403 size_t HttpClientTask::DataReceiveCallback(const void *data, size_t size, size_t memBytes, void *userData)
404 {
405     unsigned int taskId = *reinterpret_cast<unsigned int *>(userData);
406     NETSTACK_LOGD("taskId=%{public}d size=%{public}zu memBytes=%{public}zu",
407                   taskId, size, memBytes);
408 
409     auto task = HttpSession::GetInstance().GetTaskById(taskId);
410     if (task == nullptr) {
411         NETSTACK_LOGE("task == nullptr");
412         return 0;
413     }
414 
415     if (task->canceled_) {
416         NETSTACK_LOGD("canceled");
417         return 0;
418     }
419 
420     if (task->onDataReceive_) {
421         HttpClientRequest request = task->request_;
422         task->onDataReceive_(request, static_cast<const uint8_t *>(data), size * memBytes);
423     }
424 
425     if (task->response_.GetResult().size() < MAX_LIMIT) {
426         task->response_.AppendResult(data, size * memBytes);
427     }
428 
429     return size * memBytes;
430 }
431 
ProgressCallback(void * userData,curl_off_t dltotal,curl_off_t dlnow,curl_off_t ultotal,curl_off_t ulnow)432 int HttpClientTask::ProgressCallback(void *userData, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal,
433                                      curl_off_t ulnow)
434 {
435     unsigned int taskId = *reinterpret_cast<unsigned int *>(userData);
436     NETSTACK_LOGD("taskId=%{public}d dltotal=%{public}" CURL_FORMAT_CURL_OFF_T
437                   " dlnow=%{public}" CURL_FORMAT_CURL_OFF_T " ultotal=%{public}" CURL_FORMAT_CURL_OFF_T
438                   " ulnow=%{public}" CURL_FORMAT_CURL_OFF_T,
439                   taskId, dltotal, dlnow, ultotal, ulnow);
440 
441     auto task = HttpSession::GetInstance().GetTaskById(taskId);
442     if (task == nullptr) {
443         NETSTACK_LOGE("HttpClientTask::ProgressCallback() task == nullptr");
444         return 0;
445     }
446 
447     if (task->canceled_) {
448         NETSTACK_LOGD("canceled");
449         return CURLE_ABORTED_BY_CALLBACK;
450     }
451 
452     if (task->onProgress_) {
453         task->onProgress_(task->request_, dltotal, dlnow, ultotal, ulnow);
454     }
455 
456     return 0;
457 }
458 
HeaderReceiveCallback(const void * data,size_t size,size_t memBytes,void * userData)459 size_t HttpClientTask::HeaderReceiveCallback(const void *data, size_t size, size_t memBytes, void *userData)
460 {
461     unsigned int taskId = *reinterpret_cast<unsigned int *>(userData);
462     NETSTACK_LOGD("taskId=%{public}d size=%{public}zu memBytes=%{public}zu",
463                   taskId, size, memBytes);
464 
465     if (size * memBytes > MAX_LIMIT) {
466         NETSTACK_LOGE("size * memBytes(%{public}zu) > MAX_LIMIT(%{public}zu)",
467                       size * memBytes, MAX_LIMIT);
468         return 0;
469     }
470 
471     auto task = HttpSession::GetInstance().GetTaskById(taskId);
472     if (task == nullptr) {
473         NETSTACK_LOGE("HttpClientTask::HeaderReceiveCallback() task == nullptr");
474         return 0;
475     }
476 
477     task->response_.AppendHeader(static_cast<const char *>(data), size * memBytes);
478 
479     return size * memBytes;
480 }
481 
ProcessCookie(CURL * handle)482 void HttpClientTask::ProcessCookie(CURL *handle)
483 {
484     struct curl_slist *cookies = nullptr;
485     if (handle == nullptr) {
486         NETSTACK_LOGE("HttpClientTask::ProcessCookie() handle == nullptr");
487         return;
488     }
489 
490     CURLcode res = curl_easy_getinfo(handle, CURLINFO_COOKIELIST, &cookies);
491     if (res != CURLE_OK) {
492         NETSTACK_LOGE("HttpClientTask::ProcessCookie() curl_easy_getinfo() error! res = %{public}d", res);
493         return;
494     }
495 
496     while (cookies) {
497         response_.AppendCookies(cookies->data, strlen(cookies->data));
498         if (cookies->next != nullptr) {
499             response_.AppendCookies(HttpConstant::HTTP_LINE_SEPARATOR, strlen(HttpConstant::HTTP_LINE_SEPARATOR));
500         }
501         cookies = cookies->next;
502     }
503 
504     NETSTACK_LOGD("ProcessCookie() GetCookies() = %{public}s", response_.GetCookies().c_str());
505     NETSTACK_LOGD("ProcessCookie() GetHeader() = %{public}s", response_.GetHeader().c_str());
506 }
507 
ProcessResponseCode()508 bool HttpClientTask::ProcessResponseCode()
509 {
510     int64_t result = 0;
511     CURLcode code = curl_easy_getinfo(curlHandle_, CURLINFO_RESPONSE_CODE, &result);
512     if (code != CURLE_OK) {
513         error_.SetCURLResult(code);
514         return false;
515     }
516     ResponseCode resultCode = static_cast<ResponseCode>(result);
517     NETSTACK_LOGI("taskid=%{public}d, responseCode=%{public}d", taskId_, resultCode);
518     response_.SetResponseCode(resultCode);
519 
520     return true;
521 }
522 
GetTimingFromCurl(CURL * handle,CURLINFO info)523 double HttpClientTask::GetTimingFromCurl(CURL *handle, CURLINFO info)
524 {
525     time_t timing;
526     CURLcode result = curl_easy_getinfo(handle, info, &timing);
527     if (result != CURLE_OK) {
528         NETSTACK_LOGE("Failed to get timing: %{public}d, %{public}s", info, curl_easy_strerror(result));
529         return 0;
530     }
531     return static_cast<double>(timing);
532 }
533 
ProcessResponse(CURLMsg * msg)534 void HttpClientTask::ProcessResponse(CURLMsg *msg)
535 {
536     CURLcode code = msg->data.result;
537     NETSTACK_LOGD("taskid=%{public}d code=%{public}d", taskId_, code);
538     error_.SetCURLResult(code);
539     response_.SetResponseTime(HttpTime::GetNowTimeGMT());
540 
541     NETSTACK_LOGD("dnsTiming: %{public}lf", GetTimingFromCurl(curlHandle_, CURLINFO_NAMELOOKUP_TIME_T));
542     NETSTACK_LOGD("connectTiming: %{public}lf", GetTimingFromCurl(curlHandle_, CURLINFO_CONNECT_TIME_T));
543     NETSTACK_LOGD("tlsTiming: %{public}lf", GetTimingFromCurl(curlHandle_, CURLINFO_APPCONNECT_TIME_T));
544     NETSTACK_LOGD("firstSendTiming: %{public}lf", GetTimingFromCurl(curlHandle_, CURLINFO_PRETRANSFER_TIME_T));
545     NETSTACK_LOGD("firstRecvTiming: %{public}lf", GetTimingFromCurl(curlHandle_, CURLINFO_STARTTRANSFER_TIME_T));
546     NETSTACK_LOGD("totalTiming: %{public}lf", GetTimingFromCurl(curlHandle_, CURLINFO_TOTAL_TIME_T));
547     NETSTACK_LOGD("redirectTiming: %{public}lf", GetTimingFromCurl(curlHandle_, CURLINFO_REDIRECT_TIME_T));
548 
549     if (CURLE_ABORTED_BY_CALLBACK == code) {
550         (void)ProcessResponseCode();
551         if (onCanceled_) {
552             onCanceled_(request_, response_);
553         }
554         return;
555     }
556 
557     if (code != CURLE_OK) {
558         if (onFailed_) {
559             onFailed_(request_, response_, error_);
560         }
561         return;
562     }
563 
564     ProcessCookie(curlHandle_);
565     response_.ParseHeaders();
566 
567     if (ProcessResponseCode()) {
568         if (onSucceeded_) {
569             onSucceeded_(request_, response_);
570         }
571     } else if (onFailed_) {
572         onFailed_(request_, response_, error_);
573     }
574 }
575 
SetResponse(const HttpClientResponse & response)576 void HttpClientTask::SetResponse(const HttpClientResponse &response)
577 {
578     response_ = response;
579 }
580 } // namespace HttpClient
581 } // namespace NetStack
582 } // namespace OHOS
583