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 <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
26 #define NETSTACK_CURL_EASY_SET_OPTION(handle, opt, data) \
27 do { \
28 CURLcode result = curl_easy_setopt(handle, opt, data); \
29 if (result != CURLE_OK) { \
30 const char *err = curl_easy_strerror(result); \
31 error_.SetCURLResult(result); \
32 NETSTACK_LOGE("Failed to set option: %{public}s, %{public}s %{public}d", #opt, err, result); \
33 return false; \
34 } \
35 } while (0)
36
37 namespace OHOS {
38 namespace NetStack {
39 namespace HttpClient {
40
41 static constexpr size_t MAX_LIMIT = 5 * 1024 * 1024;
42 std::atomic<uint32_t> HttpClientTask::nextTaskId_(0);
43
CheckFilePath(const std::string & fileName,std::string & realPath)44 bool CheckFilePath(const std::string &fileName, std::string &realPath)
45 {
46 char tmpPath[PATH_MAX] = {0};
47 if (!realpath(static_cast<const char *>(fileName.c_str()), tmpPath)) {
48 NETSTACK_LOGE("file name is error");
49 return false;
50 }
51
52 realPath = tmpPath;
53 return true;
54 }
55
HttpClientTask(const HttpClientRequest & request)56 HttpClientTask::HttpClientTask(const HttpClientRequest &request)
57 : request_(request),
58 type_(DEFAULT),
59 status_(IDLE),
60 taskId_(nextTaskId_++),
61 curlHeaderList_(nullptr),
62 canceled_(false),
63 file_(nullptr)
64 {
65 NETSTACK_LOGI("HttpClientTask::HttpClientTask() taskId_=%{public}d URL=%{public}s", taskId_,
66 request_.GetURL().c_str());
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 "HttpClientTask::HttpClientTask() taskId_=%{public}d URL=%{public}s type=%{public}d filePath=%{public}s",
89 taskId_, request_.GetURL().c_str(), 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("HttpClientTask::~HttpClientTask()");
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 }
128 return CURL_HTTP_VERSION_NONE;
129 }
130
GetHttpProxyInfo(std::string & host,int32_t & port,std::string & exclusions,std::string & userpwd,bool & tunnel)131 void HttpClientTask::GetHttpProxyInfo(std::string &host, int32_t &port, std::string &exclusions, std::string &userpwd,
132 bool &tunnel)
133 {
134 if (request_.GetHttpProxyType() == HttpProxyType::USE_SPECIFIED) {
135 HttpProxy proxy = request_.GetHttpProxy();
136 host = proxy.host;
137 port = proxy.port;
138 exclusions = proxy.exclusions;
139 userpwd = proxy.userpwd;
140 tunnel = proxy.tunnel;
141 }
142 }
143
SetOtherCurlOption(CURL * handle)144 bool HttpClientTask::SetOtherCurlOption(CURL *handle)
145 {
146 // set proxy
147 std::string host, exclusions, userpwd;
148 int32_t port = 0;
149 bool tunnel = false;
150 GetHttpProxyInfo(host, port, exclusions, userpwd, tunnel);
151 if (!host.empty()) {
152 NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_PROXY, host.c_str());
153 NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_PROXYPORT, port);
154 NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
155 if (!exclusions.empty()) {
156 NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_NOPROXY, exclusions.c_str());
157 }
158 if (!userpwd.empty()) {
159 NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_PROXYUSERPWD, userpwd.c_str());
160 }
161 if (tunnel) {
162 NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_HTTPPROXYTUNNEL, 1L);
163 }
164 }
165
166 #ifdef NO_SSL_CERTIFICATION
167 // in real life, you should buy a ssl certification and rename it to /etc/ssl/cert.pem
168 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_SSL_VERIFYHOST, 0L);
169 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_SSL_VERIFYPEER, 0L);
170 #else
171 #ifndef WINDOWS_PLATFORM
172 NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_CAINFO, request_.GetCaPath().c_str());
173 #endif // WINDOWS_PLATFORM
174 #endif // NO_SSL_CERTIFICATION
175
176 #ifdef HTTP_CURL_PRINT_VERBOSE
177 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_VERBOSE, 1L);
178 #endif
179
180 #ifndef WINDOWS_PLATFORM
181 NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_ACCEPT_ENCODING, HttpConstant::HTTP_CONTENT_ENCODING_GZIP);
182 #endif
183
184 return true;
185 }
186
SetUploadOptions(CURL * handle)187 bool HttpClientTask::SetUploadOptions(CURL *handle)
188 {
189 if (filePath_.empty()) {
190 NETSTACK_LOGE("HttpClientTask::SetUploadOptions() filePath_ is empty");
191 error_.SetErrorCode(HttpErrorCode::HTTP_UPLOAD_FAILED);
192 return false;
193 }
194
195 std::string realPath;
196 if (!CheckFilePath(filePath_, realPath)) {
197 NETSTACK_LOGE("filePath_ does not exist! ");
198 error_.SetErrorCode(HttpErrorCode::HTTP_UPLOAD_FAILED);
199 return false;
200 }
201
202 file_ = fopen(realPath.c_str(), "rb");
203 if (file_ == nullptr) {
204 NETSTACK_LOGE("HttpClientTask::SetUploadOptions() Failed to open file %{public}s", realPath.c_str());
205 error_.SetErrorCode(HttpErrorCode::HTTP_UPLOAD_FAILED);
206 return false;
207 }
208
209 NETSTACK_LOGI("HttpClientTask::SetUploadOptions() filePath_=%{public}s", realPath.c_str());
210 fseek(file_, 0, SEEK_END);
211 long size = ftell(file_);
212 rewind(file_);
213
214 // Set the file data and file size to upload
215 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_READDATA, file_);
216 NETSTACK_LOGI("HttpClientTask::SetUploadOptions() CURLOPT_INFILESIZE=%{public}ld", size);
217 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_INFILESIZE, size);
218 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_UPLOAD, 1L);
219
220 return true;
221 }
222
SetCurlOptions()223 bool HttpClientTask::SetCurlOptions()
224 {
225 auto method = request_.GetMethod();
226 if (method == HttpConstant::HTTP_METHOD_HEAD) {
227 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_NOBODY, 1L);
228 }
229
230 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_URL, request_.GetURL().c_str());
231
232 if (type_ == TaskType::UPLOAD) {
233 if (!SetUploadOptions(curlHandle_)) {
234 return false;
235 }
236 } else {
237 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_CUSTOMREQUEST, request_.GetMethod().c_str());
238
239 if ((method == HttpConstant::HTTP_METHOD_POST || method == HttpConstant::HTTP_METHOD_PUT) &&
240 !request_.GetBody().empty()) {
241 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_POST, 1L);
242 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_POSTFIELDS, request_.GetBody().c_str());
243 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_POSTFIELDSIZE, request_.GetBody().size());
244 }
245 }
246
247 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_XFERINFOFUNCTION, ProgressCallback);
248 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_XFERINFODATA, &taskId_);
249 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_NOPROGRESS, 0L);
250
251 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_WRITEFUNCTION, DataReceiveCallback);
252 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_WRITEDATA, &taskId_);
253
254 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_HEADERFUNCTION, HeaderReceiveCallback);
255 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_HEADERDATA, &taskId_);
256
257 if (curlHeaderList_ != nullptr) {
258 curl_slist_free_all(curlHeaderList_);
259 curlHeaderList_ = nullptr;
260 }
261 for (const auto &header : request_.GetHeaders()) {
262 std::string headerStr = header.first + HttpConstant::HTTP_HEADER_SEPARATOR + header.second;
263 curlHeaderList_ = curl_slist_append(curlHeaderList_, headerStr.c_str());
264 }
265 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_HTTPHEADER, curlHeaderList_);
266
267 // Some servers don't like requests that are made without a user-agent field, so we provide one
268 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_USERAGENT, HttpConstant::HTTP_DEFAULT_USER_AGENT);
269
270 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_FOLLOWLOCATION, 1L);
271
272 /* first #undef CURL_DISABLE_COOKIES in curl config */
273 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_COOKIEFILE, "");
274
275 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_NOSIGNAL, 1L);
276
277 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_TIMEOUT_MS, request_.GetTimeout());
278 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_CONNECTTIMEOUT_MS, request_.GetConnectTimeout());
279
280 NETSTACK_CURL_EASY_SET_OPTION(curlHandle_, CURLOPT_HTTP_VERSION, GetHttpVersion(request_.GetHttpProtocol()));
281
282 if (!SetOtherCurlOption(curlHandle_)) {
283 return false;
284 }
285
286 return true;
287 }
288
Start()289 bool HttpClientTask::Start()
290 {
291 auto task = shared_from_this();
292 if (task->GetStatus() != TaskStatus::IDLE) {
293 NETSTACK_LOGI("HttpClientTask::Start() task is running, taskId_=%{public}d", task->GetTaskId());
294 return false;
295 }
296
297 if (!CommonUtils::HasInternetPermission()) {
298 NETSTACK_LOGE("HttpClientTask::Start() Don't Has Internet Permission()");
299 error_.SetErrorCode(HttpErrorCode::HTTP_PERMISSION_DENIED_CODE);
300 return false;
301 }
302
303 if (error_.GetErrorCode() != HttpErrorCode::HTTP_NONE_ERR) {
304 NETSTACK_LOGE("HttpClientTask::Start() error_.GetErrorCode()=%{public}d", error_.GetErrorCode());
305 return false;
306 }
307
308 request_.SetRequestTime(HttpTime::GetNowTimeGMT());
309
310 HttpSession &session = HttpSession::GetInstance();
311 NETSTACK_LOGD("HttpClientTask::Start() taskId_=%{public}d", taskId_);
312 task->canceled_ = false;
313
314 response_.SetRequestTime(HttpTime::GetNowTimeGMT());
315 session.StartTask(task);
316
317 return true;
318 }
319
Cancel()320 void HttpClientTask::Cancel()
321 {
322 canceled_ = true;
323 }
324
SetStatus(TaskStatus status)325 void HttpClientTask::SetStatus(TaskStatus status)
326 {
327 status_ = status;
328 }
329
GetStatus()330 TaskStatus HttpClientTask::GetStatus()
331 {
332 return status_;
333 }
334
GetType()335 TaskType HttpClientTask::GetType()
336 {
337 return type_;
338 }
339
GetFilePath()340 const std::string &HttpClientTask::GetFilePath()
341 {
342 return filePath_;
343 }
344
GetTaskId()345 unsigned int HttpClientTask::GetTaskId()
346 {
347 return taskId_;
348 }
349
OnSuccess(const std::function<void (const HttpClientRequest & request,const HttpClientResponse & response)> & onSucceeded)350 void HttpClientTask::OnSuccess(
351 const std::function<void(const HttpClientRequest &request, const HttpClientResponse &response)> &onSucceeded)
352 {
353 onSucceeded_ = onSucceeded;
354 }
355
OnCancel(const std::function<void (const HttpClientRequest & request,const HttpClientResponse & response)> & onCanceled)356 void HttpClientTask::OnCancel(
357 const std::function<void(const HttpClientRequest &request, const HttpClientResponse &response)> &onCanceled)
358 {
359 onCanceled_ = onCanceled;
360 }
361
OnFail(const std::function<void (const HttpClientRequest & request,const HttpClientResponse & response,const HttpClientError & error)> & onFailed)362 void HttpClientTask::OnFail(
363 const std::function<void(const HttpClientRequest &request, const HttpClientResponse &response,
364 const HttpClientError &error)> &onFailed)
365 {
366 onFailed_ = onFailed;
367 }
368
OnDataReceive(const std::function<void (const HttpClientRequest & request,const uint8_t * data,size_t length)> & onDataReceive)369 void HttpClientTask::OnDataReceive(
370 const std::function<void(const HttpClientRequest &request, const uint8_t *data, size_t length)> &onDataReceive)
371 {
372 onDataReceive_ = onDataReceive;
373 }
374
OnProgress(const std::function<void (const HttpClientRequest & request,u_long dlTotal,u_long dlNow,u_long ulTotal,u_long ulNow)> & onProgress)375 void HttpClientTask::OnProgress(const std::function<void(const HttpClientRequest &request, u_long dlTotal, u_long dlNow,
376 u_long ulTotal, u_long ulNow)> &onProgress)
377 {
378 onProgress_ = onProgress;
379 }
380
DataReceiveCallback(const void * data,size_t size,size_t memBytes,void * userData)381 size_t HttpClientTask::DataReceiveCallback(const void *data, size_t size, size_t memBytes, void *userData)
382 {
383 unsigned int taskId = *reinterpret_cast<unsigned int *>(userData);
384 NETSTACK_LOGD("HttpClientTask::DataReceiveCallback() taskId=%{public}d size=%{public}zu memBytes=%{public}zu",
385 taskId, size, memBytes);
386
387 auto task = HttpSession::GetInstance().GetTaskById(taskId);
388 if (task == nullptr) {
389 NETSTACK_LOGE("HttpClientTask::DataReceiveCallback() task == nullptr");
390 return 0;
391 }
392
393 if (task->canceled_) {
394 NETSTACK_LOGD("HttpClientTask::DataReceiveCallback() canceled");
395 return 0;
396 }
397
398 if (task->onDataReceive_) {
399 HttpClientRequest request = task->request_;
400 task->onDataReceive_(request, static_cast<const uint8_t *>(data), size * memBytes);
401 }
402
403 if (task->response_.GetResult().size() < MAX_LIMIT) {
404 task->response_.AppendResult(data, size * memBytes);
405 }
406
407 return size * memBytes;
408 }
409
ProgressCallback(void * userData,curl_off_t dltotal,curl_off_t dlnow,curl_off_t ultotal,curl_off_t ulnow)410 int HttpClientTask::ProgressCallback(void *userData, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal,
411 curl_off_t ulnow)
412 {
413 unsigned int taskId = *reinterpret_cast<unsigned int *>(userData);
414 NETSTACK_LOGD("HttpClientTask::ProgressCallback() taskId=%{public}d dltotal=%{public}" CURL_FORMAT_CURL_OFF_T
415 " dlnow=%{public}" CURL_FORMAT_CURL_OFF_T " ultotal=%{public}" CURL_FORMAT_CURL_OFF_T
416 " ulnow=%{public}" CURL_FORMAT_CURL_OFF_T,
417 taskId, dltotal, dlnow, ultotal, ulnow);
418
419 auto task = HttpSession::GetInstance().GetTaskById(taskId);
420 if (task == nullptr) {
421 NETSTACK_LOGE("HttpClientTask::ProgressCallback() task == nullptr");
422 return 0;
423 }
424
425 if (task->canceled_) {
426 NETSTACK_LOGI("HttpClientTask::ProgressCallback() canceled");
427 return CURLE_ABORTED_BY_CALLBACK;
428 }
429
430 if (task->onProgress_) {
431 task->onProgress_(task->request_, dltotal, dlnow, ultotal, ulnow);
432 }
433
434 return 0;
435 }
436
HeaderReceiveCallback(const void * data,size_t size,size_t memBytes,void * userData)437 size_t HttpClientTask::HeaderReceiveCallback(const void *data, size_t size, size_t memBytes, void *userData)
438 {
439 unsigned int taskId = *reinterpret_cast<unsigned int *>(userData);
440 NETSTACK_LOGD("HttpClientTask::HeaderReceiveCallback() taskId=%{public}d size=%{public}zu memBytes=%{public}zu",
441 taskId, size, memBytes);
442
443 if (size * memBytes > MAX_LIMIT) {
444 NETSTACK_LOGE("HttpClientTask::HeaderReceiveCallback() size * memBytes(%{public}zu) > MAX_LIMIT(%{public}zu)",
445 size * memBytes, MAX_LIMIT);
446 return 0;
447 }
448
449 auto task = HttpSession::GetInstance().GetTaskById(taskId);
450 if (task == nullptr) {
451 NETSTACK_LOGE("HttpClientTask::HeaderReceiveCallback() task == nullptr");
452 return 0;
453 }
454
455 NETSTACK_LOGD("HttpClientTask::HeaderReceiveCallback() (const char *)data=%{public}s",
456 static_cast<const char *>(data));
457 task->response_.AppendHeader(static_cast<const char *>(data), size * memBytes);
458
459 return size * memBytes;
460 }
461
ProcessCookie(CURL * handle)462 void HttpClientTask::ProcessCookie(CURL *handle)
463 {
464 struct curl_slist *cookies = nullptr;
465 if (handle == nullptr) {
466 NETSTACK_LOGE("HttpClientTask::ProcessCookie() handle == nullptr");
467 return;
468 }
469
470 CURLcode res = curl_easy_getinfo(handle, CURLINFO_COOKIELIST, &cookies);
471 if (res != CURLE_OK) {
472 NETSTACK_LOGE("HttpClientTask::ProcessCookie() curl_easy_getinfo() error! res = %{public}d", res);
473 return;
474 }
475
476 while (cookies) {
477 response_.AppendCookies(cookies->data, strlen(cookies->data));
478 if (cookies->next != nullptr) {
479 response_.AppendCookies(HttpConstant::HTTP_LINE_SEPARATOR, strlen(HttpConstant::HTTP_LINE_SEPARATOR));
480 }
481 cookies = cookies->next;
482 }
483
484 NETSTACK_LOGD("ProcessCookie() GetCookies() = %{public}s", response_.GetCookies().c_str());
485 NETSTACK_LOGD("ProcessCookie() GetHeader() = %{public}s", response_.GetHeader().c_str());
486 }
487
ProcessResponseCode()488 bool HttpClientTask::ProcessResponseCode()
489 {
490 CURLcode code = CURLE_OK;
491 ResponseCode responseCode = ResponseCode::NONE;
492 code = curl_easy_getinfo(curlHandle_, CURLINFO_RESPONSE_CODE, &responseCode);
493 if (code != CURLE_OK) {
494 error_.SetCURLResult(code);
495 return false;
496 }
497 NETSTACK_LOGI("HttpClientTask::ProcessResponseCode() responseCode=%{public}d", responseCode);
498 response_.SetResponseCode(responseCode);
499
500 return true;
501 }
502
ProcessResponse(CURLMsg * msg)503 void HttpClientTask::ProcessResponse(CURLMsg *msg)
504 {
505 CURLcode code = msg->data.result;
506 NETSTACK_LOGI("HttpClientTask::ProcessResponse() taskid=%{public}d code=%{public}d", taskId_, code);
507 error_.SetCURLResult(code);
508 response_.SetResponseTime(HttpTime::GetNowTimeGMT());
509
510 if (CURLE_ABORTED_BY_CALLBACK == code) {
511 (void)ProcessResponseCode();
512 if (onCanceled_) {
513 onCanceled_(request_, response_);
514 }
515 return;
516 }
517
518 if (code != CURLE_OK) {
519 if (onFailed_) {
520 onFailed_(request_, response_, error_);
521 }
522 return;
523 }
524
525 ProcessCookie(curlHandle_);
526 response_.ParseHeaders();
527
528 if (ProcessResponseCode()) {
529 if (onSucceeded_) {
530 onSucceeded_(request_, response_);
531 }
532 } else if (onFailed_) {
533 onFailed_(request_, response_, error_);
534 }
535 }
536
SetResponse(const HttpClientResponse & response)537 void HttpClientTask::SetResponse(const HttpClientResponse &response)
538 {
539 response_ = response;
540 }
541 } // namespace HttpClient
542 } // namespace NetStack
543 } // namespace OHOS
544