1 /*
2  * Copyright (c) 2023-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 #define MEDIA_PLUGIN
17 #define HST_LOG_TAG "Downloader"
18 
19 #include "avcodec_trace.h"
20 #include "downloader.h"
21 #include "osal/utils/steady_clock.h"
22 #include "securec.h"
23 #include "plugin/plugin_time.h"
24 #include "syspara/parameter.h"
25 
26 namespace OHOS {
27 namespace Media {
28 namespace Plugins {
29 namespace HttpPlugin {
30 namespace {
31 constexpr int PER_REQUEST_SIZE = 48 * 1024 * 10;
32 constexpr unsigned int SLEEP_TIME = 5;    // Sleep 5ms
33 constexpr size_t RETRY_TIMES = 6000;  // Retry 6000 times
34 constexpr size_t REQUEST_QUEUE_SIZE = 50;
35 constexpr long LIVE_CONTENT_LENGTH = 2147483646;
36 constexpr int32_t DOWNLOAD_LOG_FEQUENCE = 10;
37 constexpr int32_t LOOP_TIMES = 5;
38 constexpr int32_t MAX_LEN = 128;
39 const std::string USER_AGENT = "User-Agent";
40 const std::string DISPLAYVERSION = "const.product.software.version";
41 constexpr int FIRST_REQUEST_SIZE = 8 * 1024;
42 constexpr int MIN_REQUEST_SIZE = 2;
43 constexpr int SERVER_RANGE_ERROR_CODE = 416;
44 constexpr int32_t LOOP_LOG_FEQUENCE = 50;
45 }
46 
DownloadRequest(const std::string & url,DataSaveFunc saveData,StatusCallbackFunc statusCallback,bool requestWholeFile)47 DownloadRequest::DownloadRequest(const std::string& url, DataSaveFunc saveData, StatusCallbackFunc statusCallback,
48                                  bool requestWholeFile)
49     : url_(url), saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)),
50     requestWholeFile_(requestWholeFile)
51 {
52     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
53     headerInfo_.fileContentLen = 0;
54     headerInfo_.contentLen = 0;
55 }
56 
DownloadRequest(const std::string & url,double duration,DataSaveFunc saveData,StatusCallbackFunc statusCallback,bool requestWholeFile)57 DownloadRequest::DownloadRequest(const std::string& url,
58                                  double duration,
59                                  DataSaveFunc saveData,
60                                  StatusCallbackFunc statusCallback,
61                                  bool requestWholeFile)
62     : url_(url), duration_(duration), saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)),
63     requestWholeFile_(requestWholeFile)
64 {
65     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
66     headerInfo_.fileContentLen = 0;
67     headerInfo_.contentLen = 0;
68 }
69 
DownloadRequest(DataSaveFunc saveData,StatusCallbackFunc statusCallback,RequestInfo requestInfo,bool requestWholeFile)70 DownloadRequest::DownloadRequest(DataSaveFunc saveData, StatusCallbackFunc statusCallback, RequestInfo requestInfo,
71                                  bool requestWholeFile)
72     : saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)), requestInfo_(requestInfo),
73     requestWholeFile_(requestWholeFile)
74 {
75     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
76     headerInfo_.fileContentLen = 0;
77     headerInfo_.contentLen = 0;
78     url_ = requestInfo.url;
79     httpHeader_ = requestInfo.httpHeader;
80 }
81 
DownloadRequest(double duration,DataSaveFunc saveData,StatusCallbackFunc statusCallback,RequestInfo requestInfo,bool requestWholeFile)82 DownloadRequest::DownloadRequest(double duration,
83                                  DataSaveFunc saveData,
84                                  StatusCallbackFunc statusCallback,
85                                  RequestInfo requestInfo,
86                                  bool requestWholeFile)
87     : duration_(duration), saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)),
88     requestInfo_(requestInfo), requestWholeFile_(requestWholeFile)
89 {
90     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
91     headerInfo_.fileContentLen = 0;
92     headerInfo_.contentLen = 0;
93     url_ = requestInfo.url;
94     httpHeader_ = requestInfo.httpHeader;
95 }
96 
GetFileContentLength() const97 size_t DownloadRequest::GetFileContentLength() const
98 {
99     WaitHeaderUpdated();
100     return headerInfo_.GetFileContentLength();
101 }
102 
GetFileContentLengthNoWait() const103 size_t DownloadRequest::GetFileContentLengthNoWait() const
104 {
105     return headerInfo_.fileContentLen;
106 }
107 
SaveHeader(const HeaderInfo * header)108 void DownloadRequest::SaveHeader(const HeaderInfo* header)
109 {
110     MediaAVCodec::AVCodecTrace trace("DownloadRequest::SaveHeader");
111     headerInfo_.Update(header);
112     isHeaderUpdated = true;
113 }
114 
IsChunked(bool isInterruptNeeded)115 Seekable DownloadRequest::IsChunked(bool isInterruptNeeded)
116 {
117     isInterruptNeeded_ = isInterruptNeeded;
118     WaitHeaderUpdated();
119     if (isInterruptNeeded) {
120         MEDIA_LOG_I("Canceled");
121         return Seekable::INVALID;
122     }
123     if (headerInfo_.isChunked) {
124         return GetFileContentLength() == LIVE_CONTENT_LENGTH ? Seekable::SEEKABLE : Seekable::UNSEEKABLE;
125     } else {
126         return Seekable::SEEKABLE;
127     }
128 };
129 
IsEos() const130 bool DownloadRequest::IsEos() const
131 {
132     return isEos_;
133 }
134 
GetRetryTimes() const135 int DownloadRequest::GetRetryTimes() const
136 {
137     return retryTimes_;
138 }
139 
GetClientError() const140 int32_t DownloadRequest::GetClientError() const
141 {
142     return clientError_;
143 }
144 
GetServerError() const145 int32_t DownloadRequest::GetServerError() const
146 {
147     return serverError_;
148 }
149 
IsClosed() const150 bool DownloadRequest::IsClosed() const
151 {
152     return headerInfo_.isClosed;
153 }
154 
Close()155 void DownloadRequest::Close()
156 {
157     headerInfo_.isClosed = true;
158 }
159 
WaitHeaderUpdated() const160 void DownloadRequest::WaitHeaderUpdated() const
161 {
162     MediaAVCodec::AVCodecTrace trace("DownloadRequest::WaitHeaderUpdated");
163 
164     // Wait Header(fileContentLen etc.) updated
165     while (!isHeaderUpdated && times_ < RETRY_TIMES && !isInterruptNeeded_ && !headerInfo_.isClosed) {
166         Task::SleepInTask(SLEEP_TIME);
167         times_++;
168     }
169     uint32_t headerIsClosed = static_cast<uint32_t>(headerInfo_.isClosed.load());
170     MEDIA_LOG_D("isHeaderUpdated " PUBLIC_LOG_D32 ", times " PUBLIC_LOG_ZU ", isClosed " PUBLIC_LOG_D32,
171         isHeaderUpdated, times_, headerIsClosed);
172 }
173 
GetDuration() const174 double DownloadRequest::GetDuration() const
175 {
176     return duration_;
177 }
178 
SetStartTimePos(int64_t startTimePos)179 void DownloadRequest::SetStartTimePos(int64_t startTimePos)
180 {
181     startTimePos_ = startTimePos;
182     if (startTimePos_ > 0) {
183         shouldSaveData_ = false;
184     }
185 }
186 
SetRangePos(int64_t startPos,int64_t endPos)187 void DownloadRequest::SetRangePos(int64_t startPos, int64_t endPos)
188 {
189     startPos_ = startPos;
190     endPos_ = endPos;
191 }
192 
SetDownloadDoneCb(DownloadDoneCbFunc downloadDoneCallback)193 void DownloadRequest::SetDownloadDoneCb(DownloadDoneCbFunc downloadDoneCallback)
194 {
195     downloadDoneCallback_ = downloadDoneCallback;
196 }
197 
GetNowTime()198 int64_t DownloadRequest::GetNowTime()
199 {
200     return std::chrono::duration_cast<std::chrono::milliseconds>
201            (std::chrono::system_clock::now().time_since_epoch()).count();
202 }
203 
GetBitRate() const204 uint32_t DownloadRequest::GetBitRate() const
205 {
206     if ((downloadDoneTime_ == 0) || (downloadStartTime_ == 0) || (realRecvContentLen_ == 0)) {
207         return 0;
208     }
209     int64_t timeGap = downloadDoneTime_ - downloadStartTime_;
210     if (timeGap == 0) {
211         return 0;
212     }
213     uint32_t bitRate = static_cast<uint32_t>(realRecvContentLen_ * 1000 *
214                         1 * 8 / timeGap); // 1000:ms to sec 1:weight 8:byte to bit
215     return bitRate;
216 }
217 
IsChunkedVod() const218 bool DownloadRequest::IsChunkedVod() const
219 {
220     return headerInfo_.isChunked && headerInfo_.GetFileContentLength() == LIVE_CONTENT_LENGTH;
221 }
222 
IsM3u8Request() const223 bool DownloadRequest::IsM3u8Request() const
224 {
225     return isM3u8Request_;
226 }
227 
SetIsM3u8Request(bool isM3u8Request)228 void DownloadRequest::SetIsM3u8Request(bool isM3u8Request)
229 {
230     isM3u8Request_ = isM3u8Request;
231 }
232 
IsServerAcceptRange() const233 bool DownloadRequest::IsServerAcceptRange() const
234 {
235     if (headerInfo_.isChunked) {
236         return false;
237     }
238     return headerInfo_.isServerAcceptRange;
239 }
240 
GetLocation(std::string & location) const241 void DownloadRequest::GetLocation(std::string& location) const
242 {
243     location = location_;
244 }
245 
Downloader(const std::string & name)246 Downloader::Downloader(const std::string& name) noexcept : name_(std::move(name))
247 {
248     shouldStartNextRequest = true;
249 
250     client_ = NetworkClient::GetInstance(&RxHeaderData, &RxBodyData, this);
251     client_->Init();
252     requestQue_ = std::make_shared<BlockingQueue<std::shared_ptr<DownloadRequest>>>(name_ + "RequestQue",
253         REQUEST_QUEUE_SIZE);
254     task_ = std::make_shared<Task>(std::string("OS_" + name_ + "Downloader"));
255     task_->RegisterJob([this] {
256         {
257             AutoLock lk(loopPauseMutex_);
258             loopStatus_ = LoopStatus::START;
259         }
260         HttpDownloadLoop();
261         NotifyLoopPause();
262         return 0;
263     });
264     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader ctor", FAKE_POINTER(this));
265 }
266 
~Downloader()267 Downloader::~Downloader()
268 {
269     isDestructor_ = true;
270     MEDIA_LOG_I("~Downloader In");
271     Stop(false);
272     if (task_ != nullptr) {
273         task_ = nullptr;
274     }
275     if (client_ != nullptr) {
276         client_->Deinit();
277         client_ = nullptr;
278     }
279     MEDIA_LOG_I("0x%{public}06" PRIXPTR " ~Downloader dtor", FAKE_POINTER(this));
280 }
281 
Download(const std::shared_ptr<DownloadRequest> & request,int32_t waitMs)282 bool Downloader::Download(const std::shared_ptr<DownloadRequest>& request, int32_t waitMs)
283 {
284     MEDIA_LOG_I("In");
285     if (isInterruptNeeded_) {
286         request->isInterruptNeeded_ = true;
287     }
288     requestQue_->SetActive(true);
289     if (waitMs == -1) { // wait until push success
290         requestQue_->Push(request);
291         return true;
292     }
293     return requestQue_->Push(request, static_cast<int>(waitMs));
294 }
295 
Start()296 void Downloader::Start()
297 {
298     MediaAVCodec::AVCodecTrace trace("Downloader::Start");
299     MEDIA_LOG_I("start Begin");
300     requestQue_->SetActive(true);
301     task_->Start();
302     MEDIA_LOG_I("start End");
303 }
304 
Pause(bool isAsync)305 void Downloader::Pause(bool isAsync)
306 {
307     MediaAVCodec::AVCodecTrace trace("Downloader::Pause");
308     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Pause Begin", FAKE_POINTER(this));
309     requestQue_->SetActive(false, false);
310     if (client_ != nullptr) {
311         isClientClose_ = true;
312         client_->Close(isAsync);
313     }
314     PauseLoop(true);
315     if (!isAsync) {
316         WaitLoopPause();
317     }
318     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Pause End", FAKE_POINTER(this));
319 }
320 
Cancel()321 void Downloader::Cancel()
322 {
323     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Cancel Begin", FAKE_POINTER(this));
324     requestQue_->SetActive(false, true);
325     shouldStartNextRequest = true;
326     if (client_ != nullptr) {
327         client_->Close(false);
328     }
329     PauseLoop(true);
330     WaitLoopPause();
331     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Cancel End", FAKE_POINTER(this));
332 }
333 
334 
Resume()335 void Downloader::Resume()
336 {
337     MediaAVCodec::AVCodecTrace trace("Downloader::Resume");
338     FALSE_RETURN_MSG(!isDestructor_ && !isInterruptNeeded_, "not Resume. is Destructor or InterruptNeeded");
339     {
340         AutoLock lock(operatorMutex_);
341         MEDIA_LOG_I("resume Begin");
342         if (isClientClose_ && client_ != nullptr && currentRequest_ != nullptr) {
343             isClientClose_ = false;
344             client_->Open(currentRequest_->url_, currentRequest_->httpHeader_, currentRequest_->requestInfo_.timeoutMs);
345         }
346         requestQue_->SetActive(true);
347         if (currentRequest_ != nullptr) {
348             currentRequest_->isEos_ = false;
349         }
350     }
351     Start();
352     MEDIA_LOG_I("resume End");
353 }
354 
Stop(bool isAsync)355 void Downloader::Stop(bool isAsync)
356 {
357     MediaAVCodec::AVCodecTrace trace("Downloader::Stop");
358     MEDIA_LOG_I("Stop Begin");
359     isDestructor_ = true;
360     if (requestQue_ != nullptr) {
361         requestQue_->SetActive(false);
362     }
363     if (currentRequest_ != nullptr) {
364         currentRequest_->isInterruptNeeded_ = true;
365         currentRequest_->Close();
366     }
367     if (client_ != nullptr) {
368         client_->Close(isAsync);
369         if (!isAsync) {
370             client_->Deinit();
371         }
372     }
373     shouldStartNextRequest = true;
374     if (task_ != nullptr) {
375         if (isAsync) {
376             task_->StopAsync();
377         } else {
378             task_->Stop();
379         }
380     }
381     MEDIA_LOG_I("Stop End");
382 }
383 
Seek(int64_t offset)384 bool Downloader::Seek(int64_t offset)
385 {
386     MediaAVCodec::AVCodecTrace trace("Downloader::Seek, offset: " + std::to_string(offset));
387     FALSE_RETURN_V_MSG(!isDestructor_ && !isInterruptNeeded_, false, "not Seek. is Destructor or InterruptNeeded");
388     AutoLock lock(operatorMutex_);
389     FALSE_RETURN_V(currentRequest_ != nullptr, false);
390     size_t contentLength = currentRequest_->GetFileContentLength();
391     MEDIA_LOG_I("Seek Begin, offset = " PUBLIC_LOG_D64 ", contentLength = " PUBLIC_LOG_ZU, offset, contentLength);
392     if (offset >= 0 && offset < static_cast<int64_t>(contentLength)) {
393         currentRequest_->startPos_ = offset;
394     }
395     size_t temp = currentRequest_->GetFileContentLength() - static_cast<size_t>(currentRequest_->startPos_);
396     currentRequest_->requestSize_ = static_cast<int>(std::min(temp, static_cast<size_t>(PER_REQUEST_SIZE)));
397     if (downloadRequestSize_ > 0) {
398         currentRequest_->requestSize_ = std::min(currentRequest_->requestSize_,
399             static_cast<int>(downloadRequestSize_));
400         downloadRequestSize_ = 0;
401     }
402     currentRequest_->isEos_ = false;
403     shouldStartNextRequest = false; // Reuse last request when seek
404     if (currentRequest_->retryTimes_ > 0) {
405         currentRequest_->retryTimes_ = 0;
406     }
407     return true;
408 }
409 
SetRequestSize(size_t downloadRequestSize)410 void Downloader::SetRequestSize(size_t downloadRequestSize)
411 {
412     downloadRequestSize_ = downloadRequestSize;
413 }
414 
GetIp(std::string & ip)415 void Downloader::GetIp(std::string &ip)
416 {
417     if (client_ != nullptr) {
418         client_->GetIp(ip);
419     }
420 }
421 
422 // Pause download thread before use currentRequest_
Retry(const std::shared_ptr<DownloadRequest> & request)423 bool Downloader::Retry(const std::shared_ptr<DownloadRequest>& request)
424 {
425     FALSE_RETURN_V_MSG(client_ != nullptr && !isDestructor_ && !isInterruptNeeded_, false,
426         "not Retry, client null or isDestructor or isInterruptNeeded");
427     {
428         AutoLock lock(operatorMutex_);
429         MEDIA_LOG_I("0x%{public}06" PRIXPTR " Retry Begin", FAKE_POINTER(this));
430         FALSE_RETURN_V(client_ != nullptr && !shouldStartNextRequest && !isDestructor_ && !isInterruptNeeded_, false);
431         requestQue_->SetActive(false, false);
432     }
433     PauseLoop(true);
434     WaitLoopPause();
435     {
436         AutoLock lock(operatorMutex_);
437         FALSE_RETURN_V(client_ != nullptr && !shouldStartNextRequest && !isDestructor_ && !isInterruptNeeded_, false);
438         client_->Close(false);
439         if (currentRequest_ != nullptr) {
440             if (currentRequest_->IsSame(request) && !shouldStartNextRequest) {
441                 currentRequest_->retryTimes_++;
442                 currentRequest_->retryOnGoing_ = true;
443                 currentRequest_->dropedDataLen_ = 0;
444                 MEDIA_LOG_D("Do retry.");
445             }
446             client_->Open(currentRequest_->url_, currentRequest_->httpHeader_, currentRequest_->requestInfo_.timeoutMs);
447             requestQue_->SetActive(true);
448             currentRequest_->isEos_ = false;
449             if (currentRequest_->endPos_ > 0 && currentRequest_->startPos_ >= 0 &&
450                 currentRequest_->endPos_ >= currentRequest_->startPos_) {
451                 currentRequest_->requestSize_ = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
452             }
453         }
454     }
455     task_->Start();
456     return true;
457 }
458 
GetSystemParam(const std::string & key)459 std::string GetSystemParam(const std::string &key)
460 {
461     char value[MAX_LEN] = {0};
462     int32_t ret = GetParameter(key.c_str(), "", value, MAX_LEN);
463     if (ret < 0) {
464         return "";
465     }
466     return std::string(value);
467 }
468 
GetUserAgent()469 std::string GetUserAgent()
470 {
471     std::string displayVersion = GetSystemParam(DISPLAYVERSION);
472     std::string userAgent = " AVPlayerLib " + displayVersion;
473     return userAgent;
474 }
475 
BeginDownload()476 bool Downloader::BeginDownload()
477 {
478     MEDIA_LOG_I("BeginDownload");
479     std::string url = currentRequest_->url_;
480     std::map<std::string, std::string> httpHeader = currentRequest_->httpHeader_;
481 
482     if (currentRequest_->httpHeader_.count(USER_AGENT) <= 0) {
483         currentRequest_->httpHeader_[USER_AGENT] = GetUserAgent();
484         httpHeader[USER_AGENT] = GetUserAgent();
485         MEDIA_LOG_I("Set default UA.");
486     }
487 
488     int32_t timeoutMs = currentRequest_->requestInfo_.timeoutMs;
489     FALSE_RETURN_V(!url.empty(), false);
490     if (client_) {
491         client_->Open(url, httpHeader, timeoutMs);
492     }
493 
494     if (currentRequest_->endPos_ <= 0) {
495         currentRequest_->startPos_ = 0;
496         currentRequest_->requestSize_ = FIRST_REQUEST_SIZE;
497     } else {
498         int64_t temp = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
499         currentRequest_->requestSize_ = static_cast<int>(std::min(temp, static_cast<int64_t>(PER_REQUEST_SIZE)));
500     }
501     currentRequest_->isEos_ = false;
502     currentRequest_->retryTimes_ = 0;
503     currentRequest_->downloadStartTime_ = currentRequest_->GetNowTime();
504     MEDIA_LOG_I("End");
505     return true;
506 }
507 
HttpDownloadLoop()508 void Downloader::HttpDownloadLoop()
509 {
510     AutoLock lock(operatorMutex_);
511     MEDIA_LOGI_LIMIT(LOOP_LOG_FEQUENCE, "Downloader loop shouldStartNextRequest %{public}d",
512         shouldStartNextRequest.load());
513     if (shouldStartNextRequest) {
514         std::shared_ptr<DownloadRequest> tempRequest = requestQue_->Pop(1000); // 1000ms timeout limit.
515         if (!tempRequest) {
516             MEDIA_LOG_W("HttpDownloadLoop tempRequest is null.");
517             noTaskLoopTimes_++;
518             if (noTaskLoopTimes_ >= LOOP_TIMES) {
519                 PauseLoop(true);
520             }
521             return;
522         }
523         noTaskLoopTimes_ = 0;
524         currentRequest_ = tempRequest;
525         BeginDownload();
526         shouldStartNextRequest = currentRequest_->IsClosed();
527     }
528     if (currentRequest_ == nullptr || client_ == nullptr) {
529         MEDIA_LOG_I("currentRequest_ %{public}d client_ %{public}d nullptr",
530                     currentRequest_ != nullptr, client_ != nullptr);
531         PauseLoop(true);
532         return;
533     }
534     RequestData();
535     return;
536 }
537 
RequestData()538 void Downloader::RequestData()
539 {
540     MediaAVCodec::AVCodecTrace trace("Downloader::HttpDownloadLoop, startPos: "
541         + std::to_string(currentRequest_->startPos_) + ", reqSize: " + std::to_string(currentRequest_->requestSize_));
542     int64_t startPos = currentRequest_->startPos_;
543     if (currentRequest_->requestWholeFile_ && currentRequest_->shouldSaveData_) {
544         startPos = -1;
545     }
546     RequestInfo sourceInfo;
547     sourceInfo.url = currentRequest_->url_;
548     sourceInfo.httpHeader = currentRequest_->httpHeader_;
549     sourceInfo.timeoutMs = currentRequest_->requestInfo_.timeoutMs;
550 
551     auto handleResponseCb = [this](int32_t clientCode, int32_t serverCode, Status ret) {
552         currentRequest_->clientError_ = clientCode;
553         currentRequest_->serverError_ = serverCode;
554         if (isDestructor_) {
555             return;
556         }
557 
558         if (currentRequest_->requestSize_ == FIRST_REQUEST_SIZE && !currentRequest_->isFirstRangeRequestReady_
559             && currentRequest_->serverError_ == SERVER_RANGE_ERROR_CODE) {
560             MEDIA_LOG_I("first request is above filesize, need retry.");
561             currentRequest_->startPos_ = 0;
562             currentRequest_->requestSize_ = MIN_REQUEST_SIZE;
563             currentRequest_->isHeaderUpdated = false;
564             currentRequest_->isFirstRangeRequestReady_ = true;
565             currentRequest_->headerInfo_.fileContentLen = 0;
566             return;
567         }
568         if (ret == Status::OK) {
569             HandleRetOK();
570         } else {
571             PauseLoop(true);
572             MEDIA_LOG_E("Client request data failed. ret = " PUBLIC_LOG_D32 ", clientCode = " PUBLIC_LOG_D32
573                 ",request queue size: " PUBLIC_LOG_U64,
574                 static_cast<int32_t>(ret), static_cast<int32_t>(clientCode),
575                 static_cast<int64_t>(requestQue_->Size()));
576             std::shared_ptr<Downloader> unused;
577             currentRequest_->statusCallback_(DownloadStatus::PARTTAL_DOWNLOAD, unused, currentRequest_);
578         }
579     };
580     MEDIA_LOG_I("0x%{public}06" PRIXPTR " RequestData enter.", FAKE_POINTER(this));
581     client_->RequestData(startPos, currentRequest_->requestSize_, sourceInfo, handleResponseCb);
582     MEDIA_LOG_I("0x%{public}06" PRIXPTR " RequestData end.", FAKE_POINTER(this));
583 }
584 
HandlePlayingFinish()585 void Downloader::HandlePlayingFinish()
586 {
587     if (requestQue_->Empty()) {
588         PauseLoop(true);
589     }
590     shouldStartNextRequest = true;
591     if (currentRequest_->downloadDoneCallback_ && !isDestructor_) {
592         currentRequest_->downloadDoneTime_ = currentRequest_->GetNowTime();
593         currentRequest_->downloadDoneCallback_(currentRequest_->GetUrl(), currentRequest_->location_);
594         currentRequest_->isFirstRangeRequestReady_ = false;
595     }
596 }
597 
HandleRetOK()598 void Downloader::HandleRetOK()
599 {
600     if (currentRequest_->retryTimes_ > 0) {
601         currentRequest_->retryTimes_ = 0;
602     }
603     if (currentRequest_->headerInfo_.isChunked && requestQue_->Empty()) {
604         currentRequest_->isEos_ = true;
605         PauseLoop(true);
606         return;
607     }
608 
609     int64_t remaining = 0;
610     if (currentRequest_->endPos_ <= 0) {
611         remaining = static_cast<int64_t>(currentRequest_->headerInfo_.fileContentLen) -
612                     currentRequest_->startPos_;
613     } else {
614         remaining = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
615     }
616     if (currentRequest_->headerInfo_.fileContentLen > 0 && remaining <= 0) { // Check whether the playback ends.
617         MEDIA_LOG_I("http transfer reach end, startPos_ " PUBLIC_LOG_D64, currentRequest_->startPos_);
618         currentRequest_->isEos_ = true;
619         HandlePlayingFinish();
620         return;
621     }
622     if (currentRequest_->headerInfo_.fileContentLen == 0 && remaining <= 0) {
623         currentRequest_->isEos_ = true;
624         currentRequest_->Close();
625         HandlePlayingFinish();
626         return;
627     }
628     if (remaining < PER_REQUEST_SIZE) {
629         currentRequest_->requestSize_ = remaining;
630     } else {
631         currentRequest_->requestSize_ = PER_REQUEST_SIZE;
632     }
633 }
634 
UpdateHeaderInfo(Downloader * mediaDownloader)635 void Downloader::UpdateHeaderInfo(Downloader* mediaDownloader)
636 {
637     if (mediaDownloader->currentRequest_->isHeaderUpdated) {
638         return;
639     }
640     MEDIA_LOG_I("UpdateHeaderInfo enter.");
641     HeaderInfo* info = &(mediaDownloader->currentRequest_->headerInfo_);
642     if (info->contentLen > 0 && info->contentLen < LIVE_CONTENT_LENGTH) {
643         info->isChunked = false;
644     }
645     if (info->contentLen <= 0 && !mediaDownloader->currentRequest_->IsM3u8Request()) {
646         info->isChunked = true;
647     }
648     if (info->fileContentLen > 0 && info->isChunked && !mediaDownloader->currentRequest_->IsM3u8Request()) {
649         info->isChunked = false;
650     }
651     mediaDownloader->currentRequest_->SaveHeader(info);
652 }
653 
IsDropDataRetryRequest(Downloader * mediaDownloader)654 bool Downloader::IsDropDataRetryRequest(Downloader* mediaDownloader)
655 {
656     bool isWholeFileRetry = mediaDownloader->currentRequest_->requestWholeFile_ &&
657                             mediaDownloader->currentRequest_->shouldSaveData_ &&
658                             mediaDownloader->currentRequest_->retryOnGoing_;
659     if (!isWholeFileRetry) {
660         return false;
661     }
662     if (mediaDownloader->currentRequest_->startPos_ > 0) {
663         return true;
664     } else {
665         mediaDownloader->currentRequest_->retryOnGoing_ = false;
666         return false;
667     }
668 }
669 
DropRetryData(void * buffer,size_t dataLen,Downloader * mediaDownloader)670 size_t Downloader::DropRetryData(void* buffer, size_t dataLen, Downloader* mediaDownloader)
671 {
672     auto currentRequest_ = mediaDownloader->currentRequest_;
673     int64_t needDropLen = currentRequest_->startPos_ - currentRequest_->dropedDataLen_;
674     int64_t writeOffSet = -1;
675     if (needDropLen > 0) {
676         writeOffSet = needDropLen >= static_cast<int64_t>(dataLen) ? 0 : needDropLen; // 0:drop all
677     }
678     bool dropRet = false;
679     if (writeOffSet > 0) {
680         int64_t secondParam = static_cast<int64_t>(dataLen) - writeOffSet;
681         if (secondParam < 0) {
682             secondParam = 0;
683         }
684         dropRet = currentRequest_->saveData_(static_cast<uint8_t *>(buffer) + writeOffSet,
685                                              static_cast<uint32_t>(secondParam));
686         currentRequest_->dropedDataLen_ = currentRequest_->dropedDataLen_ + writeOffSet;
687         MEDIA_LOG_D("DropRetryData: last drop, droped len " PUBLIC_LOG_D64 ", startPos_ " PUBLIC_LOG_D64,
688                     currentRequest_->dropedDataLen_, currentRequest_->startPos_);
689     } else if (writeOffSet == 0) {
690         currentRequest_->dropedDataLen_ = currentRequest_->dropedDataLen_ +
691                                             static_cast<int64_t>(dataLen);
692         dropRet = true;
693         MEDIA_LOG_D("DropRetryData: drop, droped len " PUBLIC_LOG_D64 ", startPos_ " PUBLIC_LOG_D64,
694                     currentRequest_->dropedDataLen_, currentRequest_->startPos_);
695     } else {
696         MEDIA_LOG_E("drop data error");
697     }
698     if (dropRet && currentRequest_->startPos_ == currentRequest_->dropedDataLen_) {
699         currentRequest_->retryOnGoing_ = false;
700         currentRequest_->dropedDataLen_ = 0;
701         if (writeOffSet > 0) {
702             currentRequest_->startPos_ = currentRequest_->startPos_ +
703                                          static_cast<int64_t>(dataLen) - writeOffSet;
704         }
705         MEDIA_LOG_I("drop data finished, startPos_ " PUBLIC_LOG_D64, currentRequest_->startPos_);
706     }
707     return dropRet ? dataLen : 0; // 0:save data failed or drop error
708 }
709 
UpdateCurRequest(Downloader * mediaDownloader,HeaderInfo * header)710 void Downloader::UpdateCurRequest(Downloader* mediaDownloader, HeaderInfo* header)
711 {
712     int64_t hstTime = 0;
713     Sec2HstTime(mediaDownloader->currentRequest_->GetDuration(), hstTime);
714     int64_t startTimePos = mediaDownloader->currentRequest_->startTimePos_;
715     int64_t contenLen = static_cast<int64_t>(header->fileContentLen);
716     int64_t startPos = 0;
717     if (hstTime != 0) {
718         startPos = contenLen * startTimePos / (HstTime2Ns(hstTime));
719     }
720     mediaDownloader->currentRequest_->startPos_ = startPos;
721     mediaDownloader->currentRequest_->shouldSaveData_ = true;
722     mediaDownloader->currentRequest_->requestWholeFile_ = false;
723     mediaDownloader->currentRequest_->requestSize_ = PER_REQUEST_SIZE;
724     mediaDownloader->currentRequest_->startTimePos_ = 0;
725 }
726 
RxBodyData(void * buffer,size_t size,size_t nitems,void * userParam)727 size_t Downloader::RxBodyData(void* buffer, size_t size, size_t nitems, void* userParam)
728 {
729     auto mediaDownloader = static_cast<Downloader *>(userParam);
730     size_t dataLen = size * nitems;
731     int64_t curLen = mediaDownloader->currentRequest_->realRecvContentLen_;
732     int64_t realRecvContentLen = static_cast<int64_t>(dataLen) + curLen;
733     UpdateHeaderInfo(mediaDownloader);
734     MediaAVCodec::AVCodecTrace trace("Downloader::RxBodyData, dataLen: " + std::to_string(dataLen)
735         + ", realRecvContentLen: " + std::to_string(realRecvContentLen));
736     if (mediaDownloader->currentRequest_->IsClosed()) {
737         return 0;
738     }
739     if (IsDropDataRetryRequest(mediaDownloader)) {
740         return DropRetryData(buffer, dataLen, mediaDownloader);
741     }
742     HeaderInfo* header = &(mediaDownloader->currentRequest_->headerInfo_);
743     if (!mediaDownloader->currentRequest_->shouldSaveData_) {
744         UpdateCurRequest(mediaDownloader, header);
745         return dataLen;
746     }
747     if (header->fileContentLen == 0) {
748         if (header->contentLen > 0) {
749             MEDIA_LOG_W("Unsupported range, use content length as content file length");
750             header->fileContentLen = header->contentLen;
751         } else {
752             MEDIA_LOG_D("fileContentLen and contentLen are both zero.");
753         }
754     }
755     if (!mediaDownloader->currentRequest_->isDownloading_) {
756         mediaDownloader->currentRequest_->isDownloading_ = true;
757     }
758     if (!mediaDownloader->currentRequest_->saveData_(static_cast<uint8_t *>(buffer), static_cast<uint32_t>(dataLen))) {
759         MEDIA_LOG_W("Save data failed.");
760         return 0; // save data failed, make perform finished.
761     }
762     mediaDownloader->currentRequest_->realRecvContentLen_ = realRecvContentLen;
763     mediaDownloader->currentRequest_->isDownloading_ = false;
764     MEDIA_LOGI_LIMIT(DOWNLOAD_LOG_FEQUENCE, "RxBodyData: dataLen " PUBLIC_LOG_ZU ", startPos_ " PUBLIC_LOG_D64, dataLen,
765                      mediaDownloader->currentRequest_->startPos_);
766     mediaDownloader->currentRequest_->startPos_ = mediaDownloader->currentRequest_->startPos_ + dataLen;
767     return dataLen;
768 }
769 
770 namespace {
StringTrim(char * str)771 char* StringTrim(char* str)
772 {
773     if (str == nullptr) {
774         return nullptr;
775     }
776     char* p = str;
777     char* p1 = p + strlen(str) - 1;
778 
779     while (*p && isspace(static_cast<int>(*p))) {
780         p++;
781     }
782     while (p1 > p && isspace(static_cast<int>(*p1))) {
783         *p1-- = 0;
784     }
785     return p;
786 }
787 }
788 
HandleContentRange(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)789 bool Downloader::HandleContentRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
790 {
791     if (!strncmp(key, "content-range", strlen("content-range"))) {
792         char* token = strtok_s(nullptr, ":", &next);
793         FALSE_RETURN_V(token != nullptr, false);
794         char* strRange = StringTrim(token);
795         size_t start;
796         size_t end;
797         size_t fileLen;
798         FALSE_LOG_MSG(sscanf_s(strRange, "bytes %lu-%lu/%lu", &start, &end, &fileLen) != -1,
799             "sscanf get range failed");
800         if (info->fileContentLen > 0 && info->fileContentLen != fileLen) {
801             MEDIA_LOG_E("FileContentLen doesn't equal to fileLen");
802         }
803         if (info->fileContentLen == 0) {
804             info->fileContentLen = fileLen;
805         }
806     }
807     return true;
808 }
809 
HandleContentType(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)810 bool Downloader::HandleContentType(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
811 {
812     if (!strncmp(key, "content-type", strlen("content-type"))) {
813         char* token = strtok_s(nullptr, ":", &next);
814         FALSE_RETURN_V(token != nullptr, false);
815         char* type = StringTrim(token);
816         std::string tokenStr = (std::string)token;
817         MEDIA_LOG_I("content-type: " PUBLIC_LOG_S, tokenStr.c_str());
818         NZERO_LOG(memcpy_s(info->contentType, sizeof(info->contentType), type, strlen(type)));
819     }
820     return true;
821 }
822 
HandleContentEncode(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)823 bool Downloader::HandleContentEncode(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
824 {
825     if (!strncmp(key, "content-encode", strlen("content-encode"))) {
826         char* token = strtok_s(nullptr, ":", &next);
827         FALSE_RETURN_V(token != nullptr, false);
828         std::string tokenStr = (std::string)token;
829         MEDIA_LOG_I("content-encode: " PUBLIC_LOG_S, tokenStr.c_str());
830     }
831     return true;
832 }
833 
HandleContentLength(HeaderInfo * info,char * key,char * next,Downloader * mediaDownloader)834 bool Downloader::HandleContentLength(HeaderInfo* info, char* key, char* next, Downloader* mediaDownloader)
835 {
836     FALSE_RETURN_V(key != nullptr, false);
837     if (!strncmp(key, "content-length", strlen("content-length"))) {
838         FALSE_RETURN_V(next != nullptr, false);
839         char* token = strtok_s(nullptr, ":", &next);
840         FALSE_RETURN_V(token != nullptr, false);
841         if (info != nullptr && mediaDownloader != nullptr) {
842             info->contentLen = atol(StringTrim(token));
843             if (info->contentLen <= 0 && !mediaDownloader->currentRequest_->IsM3u8Request()) {
844                 info->isChunked = true;
845             }
846         }
847     }
848     return true;
849 }
850 
851 // Check if this server supports range download. (HTTP)
HandleRange(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)852 bool Downloader::HandleRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
853 {
854     if (!strncmp(key, "accept-ranges", strlen("accept-ranges"))) {
855         char* token = strtok_s(nullptr, ":", &next);
856         FALSE_RETURN_V(token != nullptr, false);
857         if (!strncmp(StringTrim(token), "bytes", strlen("bytes"))) {
858             info->isServerAcceptRange = true;
859             MEDIA_LOG_I("accept-ranges: bytes");
860         }
861     }
862     if (!strncmp(key, "content-range", strlen("content-range"))) {
863         char* token = strtok_s(nullptr, ":", &next);
864         FALSE_RETURN_V(token != nullptr, false);
865         std::string tokenStr = (std::string)token;
866         std::transform(tokenStr.begin(), tokenStr.end(), tokenStr.begin(), ::tolower);
867         if (tokenStr.find("bytes") != std::string::npos) {
868             info->isServerAcceptRange = true;
869             MEDIA_LOG_I("content-range: " PUBLIC_LOG_S, tokenStr.c_str());
870         }
871     }
872     return true;
873 }
874 
RxHeaderData(void * buffer,size_t size,size_t nitems,void * userParam)875 size_t Downloader::RxHeaderData(void* buffer, size_t size, size_t nitems, void* userParam)
876 {
877     MediaAVCodec::AVCodecTrace trace("Downloader::RxHeaderData");
878     auto mediaDownloader = reinterpret_cast<Downloader *>(userParam);
879     HeaderInfo* info = &(mediaDownloader->currentRequest_->headerInfo_);
880     if (mediaDownloader->currentRequest_->isHeaderUpdated) {
881         return size * nitems;
882     }
883     char* next = nullptr;
884     char* key = strtok_s(reinterpret_cast<char*>(buffer), ":", &next);
885     FALSE_RETURN_V(key != nullptr, size * nitems);
886     std::string keyStr = (std::string)key;
887     std::transform(keyStr.begin(), keyStr.end(), keyStr.begin(), ::tolower);
888     key = const_cast<char*>(keyStr.c_str());
889     if (!strncmp(key, "transfer-encoding", strlen("transfer-encoding"))) {
890         char* token = strtok_s(nullptr, ":", &next);
891         FALSE_RETURN_V(token != nullptr, size * nitems);
892         if (!strncmp(StringTrim(token), "chunked", strlen("chunked")) &&
893             !mediaDownloader->currentRequest_->IsM3u8Request()) {
894             info->isChunked = true;
895             if (static_cast<int32_t>(mediaDownloader->currentRequest_->url_.find(".flv") == std::string::npos)) {
896                 info->contentLen = LIVE_CONTENT_LENGTH;
897             } else {
898                 info->contentLen = 0;
899             }
900             std::string tokenStr = (std::string)token;
901             MEDIA_LOG_I("transfer-encoding: " PUBLIC_LOG_S, tokenStr.c_str());
902         }
903     }
904     if (!strncmp(key, "location", strlen("location"))) {
905         FALSE_RETURN_V(next != nullptr, size * nitems);
906         char* location = StringTrim(next);
907         mediaDownloader->currentRequest_->location_ = location;
908     }
909 
910     if (!HandleContentRange(info, key, next, size, nitems) || !HandleContentType(info, key, next, size, nitems) ||
911         !HandleContentEncode(info, key, next, size, nitems) ||
912         !HandleContentLength(info, key, next, mediaDownloader) ||
913         !HandleRange(info, key, next, size, nitems)) {
914         return size * nitems;
915     }
916 
917     return size * nitems;
918 }
919 
PauseLoop(bool isAsync)920 void Downloader::PauseLoop(bool isAsync)
921 {
922     if (task_ == nullptr) {
923         return;
924     }
925     if (isAsync) {
926         task_->PauseAsync();
927     } else {
928         task_->Pause();
929     }
930 }
931 
SetAppUid(int32_t appUid)932 void Downloader::SetAppUid(int32_t appUid)
933 {
934     if (client_) {
935         client_->SetAppUid(appUid);
936     }
937 }
938 
GetCurrentRequest()939 const std::shared_ptr<DownloadRequest>& Downloader::GetCurrentRequest()
940 {
941     return currentRequest_;
942 }
943 
SetInterruptState(bool isInterruptNeeded)944 void Downloader::SetInterruptState(bool isInterruptNeeded)
945 {
946     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader SetInterruptState %{public}d",
947         FAKE_POINTER(this), isInterruptNeeded);
948     isInterruptNeeded_ = isInterruptNeeded;
949     if (currentRequest_ != nullptr) {
950         currentRequest_->isInterruptNeeded_ = isInterruptNeeded;
951     }
952     NotifyLoopPause();
953 }
954 
NotifyLoopPause()955 void Downloader::NotifyLoopPause()
956 {
957     AutoLock lk(loopPauseMutex_);
958     if (loopStatus_ == LoopStatus::PAUSE || isInterruptNeeded_) {
959         MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader NotifyLoopPause", FAKE_POINTER(this));
960         loopStatus_ = LoopStatus::IDLE;
961         loopPauseCond_.NotifyAll();
962     } else {
963         loopStatus_ = LoopStatus::IDLE;
964         MEDIA_LOG_I("Downloader not NotifyLoopPause loopStatus %{public}d isInterruptNeeded %{public}d",
965             loopStatus_.load(), isInterruptNeeded_.load());
966     }
967 }
968 
WaitLoopPause()969 void Downloader::WaitLoopPause()
970 {
971     AutoLock lk(loopPauseMutex_);
972     if (loopStatus_ == LoopStatus::IDLE) {
973         MEDIA_LOG_I("0x%{public}06" PRIXPTR "Downloader not WaitLoopPause loopStatus is idle", FAKE_POINTER(this));
974         return;
975     }
976     MEDIA_LOG_I("0x%{public}06" PRIXPTR "Downloader WaitLoopPause task loopStatus_ %{public}d",
977         FAKE_POINTER(this), loopStatus_.load());
978     loopStatus_ = LoopStatus::PAUSE;
979     loopPauseCond_.Wait(lk, [this]() {
980         MEDIA_LOG_I("0x%{public}06" PRIXPTR " WaitLoopPause wake loopStatus %{public}d",
981             FAKE_POINTER(this), loopStatus_.load());
982         return loopStatus_ != LoopStatus::PAUSE || isInterruptNeeded_;
983     });
984 }
985 
986 }
987 }
988 }
989 }
990