1 /*
2  * Copyright (c) 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 "web_download_manager_impl.h"
17 
18 #include <cstring>
19 
20 #include "ffi_remote_data.h"
21 #include "nweb_c_api.h"
22 #include "nweb_helper.h"
23 #include "webview_log.h"
24 #include "web_download_delegate_impl.h"
25 
26 using namespace OHOS::FFI;
27 
28 namespace OHOS::Webview {
29 namespace {
30     static sptr<WebDownloadDelegateImpl> g_default_delegate;
31     static std::unordered_map<int32_t, WebDownloadDelegateImpl *> g_web_download_delegate_map;
32     static WebDownloadDelegateCallback *g_download_callback;
33 
GetWebDownloadDelegate(int32_t nwebId)34     WebDownloadDelegateImpl *GetWebDownloadDelegate(int32_t nwebId)
35     {
36         auto it = g_web_download_delegate_map.find(nwebId);
37         if (it != g_web_download_delegate_map.end()) {
38             return it->second;
39         }
40         return nullptr;
41     }
42 
DownloadBeforeStart(NWebDownloadItem *downloadItem, WebBeforeDownloadCallbackWrapper *wrapper)43     void DownloadBeforeStart(NWebDownloadItem *downloadItem, WebBeforeDownloadCallbackWrapper *wrapper)
44     {
45         WEBVIEWLOGD("[DOWNLOAD] DownloadBeforeStart.");
46         if (wrapper == nullptr) {
47             WEBVIEWLOGE("[DOWNLOAD] WebBeforeDownloadCallbackWrapper is null");
48             return;
49         }
50         int32_t nwebId = WebDownloadItem_NWebId(downloadItem);
51         WebDownloadDelegateImpl *webDownloadDelegate = GetWebDownloadDelegate(nwebId);
52         if (!webDownloadDelegate) {
53             WEBVIEWLOGD("[DOWNLOAD] donn't found delegate for nweb.");
54             webDownloadDelegate = g_default_delegate;
55         }
56 
57         if (!webDownloadDelegate) {
58             WEBVIEWLOGE("[DOWNLOAD] webDownloadDelegate is null");
59             return;
60         }
61 
62         WebDownloadItemImpl *webDownloadItem = FFIData::Create<WebDownloadItemImpl>(downloadItem);
63         // destroy download_item since copied content from download_item.
64         WebDownloadItem_Destroy(downloadItem);
65         webDownloadItem->before_download_callback = wrapper;
66         webDownloadDelegate->DownloadBeforeStart(webDownloadItem);
67     }
68 
DownloadDidUpdate(NWebDownloadItem *downloadItem, WebDownloadItemCallbackWrapper *wrapper)69     void DownloadDidUpdate(NWebDownloadItem *downloadItem, WebDownloadItemCallbackWrapper *wrapper)
70     {
71         WEBVIEWLOGI("DownloadDidUpdate.");
72         if (wrapper == nullptr) {
73             WEBVIEWLOGE("[DOWNLOAD] WebBeforeDownloadCallbackWrapper is null");
74             return;
75         }
76 
77         int32_t nwebId = WebDownloadItem_NWebId(downloadItem);
78 
79         WebDownloadDelegateImpl *webDownloadDelegate = GetWebDownloadDelegate(nwebId);
80         if (!webDownloadDelegate) {
81             WEBVIEWLOGD("[DOWNLOAD] donn't found delegate for nweb.");
82             webDownloadDelegate = g_default_delegate;
83         }
84 
85         if (!webDownloadDelegate) {
86             WEBVIEWLOGE("[DOWNLOAD] webDownloadDelegate is null");
87             return;
88         }
89         WebDownloadItemImpl *webDownloadItem = FFIData::Create<WebDownloadItemImpl>(downloadItem);
90         // destroy download_item since copied content from download_item.
91         WebDownloadItem_Destroy(downloadItem);
92         webDownloadItem->download_item_callback = wrapper;
93         switch (webDownloadItem->state) {
94             case NWebDownloadItemState::PENDING:
95                 //  When in PENDING state, chromium call downloadDidUpdate
96                 //  while file path is temporary file, just stop calling ui.
97                 webDownloadItem = nullptr;
98                 break;
99             case NWebDownloadItemState::IN_PROGRESS:
100             case NWebDownloadItemState::PAUSED:
101                 webDownloadDelegate->DownloadDidUpdate(webDownloadItem);
102                 break;
103             case NWebDownloadItemState::INTERRUPTED:
104             case NWebDownloadItemState::CANCELED:
105                 webDownloadDelegate->DownloadDidFail(webDownloadItem);
106                 break;
107             case NWebDownloadItemState::COMPLETE:
108                 webDownloadDelegate->DownloadDidFinish(webDownloadItem);
109                 break;
110             case NWebDownloadItemState::MAX_DOWNLOAD_STATE:
111             default:
112                 webDownloadItem = nullptr;
113                 break;
114         }
115     }
116     } // namespace
117 
118     // static
RegisterDownloadCallback()119     void WebDownloadManagerImpl::RegisterDownloadCallback()
120     {
121         // Only regist once.
122         if (g_download_callback == nullptr) {
123             WEBVIEWLOGI("RegisterDownloadCallback.");
124             WebDownloader_CreateDownloadDelegateCallback(&g_download_callback);
125             WebDownloader_SetDownloadBeforeStart(g_download_callback, &DownloadBeforeStart);
126             WebDownloader_SetDownloadDidUpdate(g_download_callback, &DownloadDidUpdate);
127             WebDownloadManager_PutDownloadCallback(g_download_callback);
128         } else {
129             WEBVIEWLOGE("[DOWNLOAD] had RegisterDownloadCallback.");
130         }
131     }
132 
133     // static
RemoveDownloadDelegate(WebDownloadDelegateImpl *delegate)134     void WebDownloadManagerImpl::RemoveDownloadDelegate(WebDownloadDelegateImpl *delegate)
135     {
136         auto iterator = g_web_download_delegate_map.begin();
137         while (iterator != g_web_download_delegate_map.end()) {
138             if (iterator->second == delegate) {
139                 g_web_download_delegate_map.erase(iterator++);
140             } else {
141                 iterator++;
142             }
143         }
144     }
145 
146     // static
AddDownloadDelegateForWeb(int32_t nwebId, WebDownloadDelegateImpl *delegate)147     void WebDownloadManagerImpl::AddDownloadDelegateForWeb(int32_t nwebId, WebDownloadDelegateImpl *delegate)
148     {
149         OHOS::NWeb::NWebHelper::Instance().LoadNWebSDK();
150         g_web_download_delegate_map.insert_or_assign(nwebId, delegate);
151         RegisterDownloadCallback();
152     }
153 
154     // static
SetDownloadDelegate(WebDownloadDelegateImpl *delegate)155     void WebDownloadManagerImpl::SetDownloadDelegate(WebDownloadDelegateImpl *delegate)
156     {
157         OHOS::NWeb::NWebHelper::Instance().LoadNWebSDK();
158         if (!g_default_delegate) {
159             g_default_delegate = delegate;
160             RegisterDownloadCallback();
161         }
162     }
163 
164     // static
HasValidDelegate()165     bool WebDownloadManagerImpl::HasValidDelegate()
166     {
167         if (!g_default_delegate) {
168             return false;
169         }
170 
171         return true;
172     }
173 
174     // static
ResumeDownload(const WebDownloadItemImpl *webDownload)175     void WebDownloadManagerImpl::ResumeDownload(const WebDownloadItemImpl *webDownload)
176     {
177         WEBVIEWLOGD("[DOWNLOAD] WebDownloadManager::ResumeDownload");
178         if (!webDownload) {
179             WEBVIEWLOGE("webDownload is nullptr");
180             return;
181         }
182         OHOS::NWeb::NWebHelper::Instance().LoadNWebSDK();
183         NWebDownloadItem *downloadItem = nullptr;
184         WebDownloadItem_CreateWebDownloadItem(&downloadItem);
185         WebDownloadItem_SetGuid(downloadItem, webDownload->guid.c_str());
186         WebDownloadItem_SetUrl(downloadItem, webDownload->url.c_str());
187         WebDownloadItem_SetFullPath(downloadItem, webDownload->fullPath.c_str());
188         WebDownloadItem_SetETag(downloadItem, webDownload->etag.c_str());
189         WebDownloadItem_SetMimeType(downloadItem, webDownload->mimeType.c_str());
190         WebDownloadItem_SetReceivedBytes(downloadItem, webDownload->receivedBytes);
191         WebDownloadItem_SetTotalBytes(downloadItem, webDownload->totalBytes);
192         WebDownloadItem_SetReceivedSlices(downloadItem, webDownload->receivedSlices.c_str());
193         WebDownloadItem_SetLastModified(downloadItem, webDownload->lastModified.c_str());
194         WebDownloader_ResumeDownloadStatic(downloadItem);
195         return;
196     }
197 } // namespace NWeb
198