Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "content/browser/renderer_host/drop_data_util.h" |
| 6 | |
| 7 | #include <string> |
| 8 | #include <utility> |
| 9 | #include <vector> |
| 10 | |
Henrique Ferreiro | a6ea10e5 | 2020-10-27 12:21:25 | [diff] [blame] | 11 | #include "base/check.h" |
Ken Rockot | c73e50a7 | 2020-10-27 00:32:23 | [diff] [blame] | 12 | #include "base/containers/span.h" |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 13 | #include "base/files/file_path.h" |
Henrique Ferreiro | a6ea10e5 | 2020-10-27 12:21:25 | [diff] [blame] | 14 | #include "base/optional.h" |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 15 | #include "base/strings/utf_string_conversions.h" |
Yuta Hijikata | 03508311 | 2020-11-11 07:02:33 | [diff] [blame] | 16 | #include "build/chromeos_buildflags.h" |
Austin Sullivan | 559bb38 | 2021-01-26 00:52:43 | [diff] [blame^] | 17 | #include "content/browser/file_system_access/file_system_access_manager_impl.h" |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 18 | #include "mojo/public/cpp/bindings/pending_remote.h" |
| 19 | #include "services/network/public/mojom/referrer_policy.mojom-shared.h" |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 20 | #include "storage/browser/file_system/external_mount_points.h" |
Austin Sullivan | d35c3346 | 2021-01-06 21:16:32 | [diff] [blame] | 21 | #include "third_party/blink/public/mojom/file_system_access/file_system_access_drag_drop_token.mojom.h" |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 22 | #include "third_party/blink/public/mojom/page/drag.mojom.h" |
| 23 | #include "ui/base/clipboard/clipboard_constants.h" |
| 24 | #include "ui/base/dragdrop/file_info/file_info.h" |
| 25 | #include "url/gurl.h" |
| 26 | |
| 27 | namespace content { |
| 28 | |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 29 | namespace { |
| 30 | |
| 31 | // On Chrome OS paths that exist on an external mount point need to be treated |
Austin Sullivan | 559bb38 | 2021-01-26 00:52:43 | [diff] [blame^] | 32 | // differently to make sure the File System Access code accesses these paths via |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 33 | // the correct file system backend. This method checks if this is the case, and |
Austin Sullivan | 559bb38 | 2021-01-26 00:52:43 | [diff] [blame^] | 34 | // updates `entry_path` to the path that should be used by the File System |
| 35 | // Access implementation. |
Austin Sullivan | afefb72 | 2021-01-14 01:26:39 | [diff] [blame] | 36 | content::FileSystemAccessEntryFactory::PathType MaybeRemapPath( |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 37 | base::FilePath* entry_path) { |
Yuta Hijikata | 03508311 | 2020-11-11 07:02:33 | [diff] [blame] | 38 | #if BUILDFLAG(IS_CHROMEOS_ASH) |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 39 | base::FilePath virtual_path; |
| 40 | auto* external_mount_points = |
| 41 | storage::ExternalMountPoints::GetSystemInstance(); |
| 42 | if (external_mount_points->GetVirtualPath(*entry_path, &virtual_path)) { |
| 43 | *entry_path = std::move(virtual_path); |
Austin Sullivan | afefb72 | 2021-01-14 01:26:39 | [diff] [blame] | 44 | return content::FileSystemAccessEntryFactory::PathType::kExternal; |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 45 | } |
| 46 | #endif |
Austin Sullivan | afefb72 | 2021-01-14 01:26:39 | [diff] [blame] | 47 | return content::FileSystemAccessEntryFactory::PathType::kLocal; |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 48 | } |
| 49 | |
| 50 | } // namespace |
| 51 | |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 52 | blink::mojom::DragDataPtr DropDataToDragData( |
| 53 | const DropData& drop_data, |
Austin Sullivan | 559bb38 | 2021-01-26 00:52:43 | [diff] [blame^] | 54 | FileSystemAccessManagerImpl* file_system_access_manager, |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 55 | int child_id) { |
| 56 | // These fields are currently unused when dragging into Blink. |
| 57 | DCHECK(drop_data.download_metadata.empty()); |
| 58 | DCHECK(drop_data.file_contents.empty()); |
| 59 | DCHECK(drop_data.file_contents_content_disposition.empty()); |
| 60 | |
| 61 | std::vector<blink::mojom::DragItemPtr> items; |
| 62 | if (drop_data.text) { |
| 63 | blink::mojom::DragItemStringPtr item = blink::mojom::DragItemString::New(); |
| 64 | item->string_type = ui::kMimeTypeText; |
| 65 | item->string_data = *drop_data.text; |
| 66 | items.push_back(blink::mojom::DragItem::NewString(std::move(item))); |
| 67 | } |
| 68 | if (!drop_data.url.is_empty()) { |
| 69 | blink::mojom::DragItemStringPtr item = blink::mojom::DragItemString::New(); |
| 70 | item->string_type = ui::kMimeTypeURIList; |
| 71 | item->string_data = base::UTF8ToUTF16(drop_data.url.spec()); |
| 72 | item->title = drop_data.url_title; |
| 73 | items.push_back(blink::mojom::DragItem::NewString(std::move(item))); |
| 74 | } |
| 75 | if (drop_data.html) { |
| 76 | blink::mojom::DragItemStringPtr item = blink::mojom::DragItemString::New(); |
| 77 | item->string_type = ui::kMimeTypeHTML; |
| 78 | item->string_data = *drop_data.html; |
| 79 | item->base_url = drop_data.html_base_url; |
| 80 | items.push_back(blink::mojom::DragItem::NewString(std::move(item))); |
| 81 | } |
| 82 | for (const ui::FileInfo& file : drop_data.filenames) { |
| 83 | blink::mojom::DragItemFilePtr item = blink::mojom::DragItemFile::New(); |
| 84 | item->path = file.path; |
| 85 | item->display_name = file.display_name; |
Austin Sullivan | d35c3346 | 2021-01-06 21:16:32 | [diff] [blame] | 86 | mojo::PendingRemote<blink::mojom::FileSystemAccessDragDropToken> |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 87 | pending_token; |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 88 | base::FilePath entry_path = file.path; |
Austin Sullivan | 559bb38 | 2021-01-26 00:52:43 | [diff] [blame^] | 89 | FileSystemAccessManagerImpl::PathType path_type = |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 90 | MaybeRemapPath(&entry_path); |
Austin Sullivan | 559bb38 | 2021-01-26 00:52:43 | [diff] [blame^] | 91 | file_system_access_manager->CreateFileSystemAccessDragDropToken( |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 92 | path_type, entry_path, child_id, |
| 93 | pending_token.InitWithNewPipeAndPassReceiver()); |
Austin Sullivan | d35c3346 | 2021-01-06 21:16:32 | [diff] [blame] | 94 | item->file_system_access_token = std::move(pending_token); |
Marijn Kruisselbrink | c100047 | 2020-10-01 22:19:54 | [diff] [blame] | 95 | |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 96 | items.push_back(blink::mojom::DragItem::NewFile(std::move(item))); |
| 97 | } |
| 98 | for (const content::DropData::FileSystemFileInfo& file_system_file : |
| 99 | drop_data.file_system_files) { |
| 100 | blink::mojom::DragItemFileSystemFilePtr item = |
| 101 | blink::mojom::DragItemFileSystemFile::New(); |
| 102 | item->url = file_system_file.url; |
| 103 | item->size = file_system_file.size; |
| 104 | item->file_system_id = file_system_file.filesystem_id; |
| 105 | items.push_back(blink::mojom::DragItem::NewFileSystemFile(std::move(item))); |
| 106 | } |
| 107 | for (const std::pair<base::string16, base::string16> data : |
| 108 | drop_data.custom_data) { |
| 109 | blink::mojom::DragItemStringPtr item = blink::mojom::DragItemString::New(); |
| 110 | item->string_type = base::UTF16ToUTF8(data.first); |
| 111 | item->string_data = data.second; |
| 112 | items.push_back(blink::mojom::DragItem::NewString(std::move(item))); |
| 113 | } |
| 114 | |
Henrique Ferreiro | a6ea10e5 | 2020-10-27 12:21:25 | [diff] [blame] | 115 | return blink::mojom::DragData::New( |
| 116 | std::move(items), |
| 117 | // While this shouldn't be a problem in production code, as the |
| 118 | // real file_system_id should never be empty if used in browser to |
| 119 | // renderer messages, some tests use this function to test renderer to |
| 120 | // browser messages, in which case the field is unused and this will hit |
| 121 | // a DCHECK. |
| 122 | drop_data.filesystem_id.empty() |
| 123 | ? base::nullopt |
| 124 | : base::Optional<std::string>( |
| 125 | base::UTF16ToUTF8(drop_data.filesystem_id)), |
| 126 | drop_data.referrer_policy); |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 127 | } |
| 128 | |
Dave Tapuska | d2a5520 | 2020-10-27 17:08:11 | [diff] [blame] | 129 | blink::mojom::DragDataPtr DropMetaDataToDragData( |
| 130 | const std::vector<DropData::Metadata>& drop_meta_data) { |
| 131 | std::vector<blink::mojom::DragItemPtr> items; |
| 132 | |
| 133 | for (const auto& meta_data_item : drop_meta_data) { |
| 134 | if (meta_data_item.kind == DropData::Kind::STRING) { |
| 135 | blink::mojom::DragItemStringPtr item = |
| 136 | blink::mojom::DragItemString::New(); |
| 137 | item->string_type = base::UTF16ToUTF8(meta_data_item.mime_type); |
| 138 | // Have to pass a dummy URL here instead of an empty URL because the |
| 139 | // DropData received by browser_plugins goes through a round trip: |
| 140 | // DropData::MetaData --> WebDragData-->DropData. In the end, DropData |
| 141 | // will contain an empty URL (which means no URL is dragged) if the URL in |
| 142 | // WebDragData is empty. |
| 143 | if (base::EqualsASCII(meta_data_item.mime_type, ui::kMimeTypeURIList)) { |
| 144 | item->string_data = base::UTF8ToUTF16("about:dragdrop-placeholder"); |
| 145 | } |
| 146 | items.push_back(blink::mojom::DragItem::NewString(std::move(item))); |
| 147 | continue; |
| 148 | } |
| 149 | |
| 150 | // TODO(hush): crbug.com/584789. Blink needs to support creating a file with |
| 151 | // just the mimetype. This is needed to drag files to WebView on Android |
| 152 | // platform. |
| 153 | if ((meta_data_item.kind == DropData::Kind::FILENAME) && |
| 154 | !meta_data_item.filename.empty()) { |
| 155 | blink::mojom::DragItemFilePtr item = blink::mojom::DragItemFile::New(); |
| 156 | item->path = meta_data_item.filename; |
| 157 | items.push_back(blink::mojom::DragItem::NewFile(std::move(item))); |
| 158 | continue; |
| 159 | } |
| 160 | |
| 161 | if (meta_data_item.kind == DropData::Kind::FILESYSTEMFILE) { |
| 162 | blink::mojom::DragItemFileSystemFilePtr item = |
| 163 | blink::mojom::DragItemFileSystemFile::New(); |
| 164 | item->url = meta_data_item.file_system_url; |
| 165 | items.push_back( |
| 166 | blink::mojom::DragItem::NewFileSystemFile(std::move(item))); |
| 167 | continue; |
| 168 | } |
| 169 | } |
| 170 | return blink::mojom::DragData::New(std::move(items), base::nullopt, |
| 171 | network::mojom::ReferrerPolicy::kDefault); |
| 172 | } |
| 173 | |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 174 | DropData DragDataToDropData(const blink::mojom::DragData& drag_data) { |
Henrique Ferreiro | a6ea10e5 | 2020-10-27 12:21:25 | [diff] [blame] | 175 | // This field should be empty when dragging from the renderer. |
| 176 | DCHECK(!drag_data.file_system_id); |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 177 | |
Henrique Ferreiro | a6ea10e5 | 2020-10-27 12:21:25 | [diff] [blame] | 178 | DropData result; |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 179 | for (const blink::mojom::DragItemPtr& item : drag_data.items) { |
| 180 | switch (item->which()) { |
| 181 | case blink::mojom::DragItemDataView::Tag::STRING: { |
| 182 | const blink::mojom::DragItemStringPtr& string_item = item->get_string(); |
| 183 | std::string str_type = string_item->string_type; |
| 184 | if (str_type == ui::kMimeTypeText) { |
| 185 | result.text = string_item->string_data; |
| 186 | } else if (str_type == ui::kMimeTypeURIList) { |
| 187 | result.url = GURL(string_item->string_data); |
| 188 | if (string_item->title) |
| 189 | result.url_title = *string_item->title; |
| 190 | } else if (str_type == ui::kMimeTypeDownloadURL) { |
| 191 | result.download_metadata = string_item->string_data; |
| 192 | result.referrer_policy = drag_data.referrer_policy; |
| 193 | } else if (str_type == ui::kMimeTypeHTML) { |
| 194 | result.html = string_item->string_data; |
| 195 | if (string_item->base_url) |
| 196 | result.html_base_url = *string_item->base_url; |
| 197 | } else { |
| 198 | result.custom_data.emplace( |
| 199 | base::UTF8ToUTF16(string_item->string_type), |
| 200 | string_item->string_data); |
| 201 | } |
| 202 | break; |
| 203 | } |
| 204 | case blink::mojom::DragItemDataView::Tag::BINARY: { |
| 205 | DCHECK(result.file_contents.empty()); |
| 206 | |
| 207 | const blink::mojom::DragItemBinaryPtr& binary_item = item->get_binary(); |
Ken Rockot | c73e50a7 | 2020-10-27 00:32:23 | [diff] [blame] | 208 | base::span<const uint8_t> contents = base::make_span(binary_item->data); |
Henrique Ferreiro | 35b04f2 | 2020-10-05 09:18:39 | [diff] [blame] | 209 | result.file_contents.assign(contents.begin(), contents.end()); |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 210 | result.file_contents_source_url = binary_item->source_url; |
| 211 | result.file_contents_filename_extension = |
| 212 | binary_item->filename_extension.value(); |
| 213 | if (binary_item->content_disposition) { |
| 214 | result.file_contents_content_disposition = |
| 215 | *binary_item->content_disposition; |
| 216 | } |
| 217 | break; |
| 218 | } |
| 219 | case blink::mojom::DragItemDataView::Tag::FILE: { |
| 220 | const blink::mojom::DragItemFilePtr& file_item = item->get_file(); |
| 221 | // TODO(varunjain): This only works on chromeos. Support win/mac/gtk. |
| 222 | result.filenames.emplace_back(file_item->path, file_item->display_name); |
| 223 | break; |
| 224 | } |
| 225 | case blink::mojom::DragItemDataView::Tag::FILE_SYSTEM_FILE: { |
| 226 | const blink::mojom::DragItemFileSystemFilePtr& file_system_file_item = |
| 227 | item->get_file_system_file(); |
Henrique Ferreiro | a6ea10e5 | 2020-10-27 12:21:25 | [diff] [blame] | 228 | // This field should be empty when dragging from the renderer. |
| 229 | DCHECK(!file_system_file_item->file_system_id); |
| 230 | |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 231 | DropData::FileSystemFileInfo info; |
| 232 | info.url = file_system_file_item->url; |
| 233 | info.size = file_system_file_item->size; |
Henrique Ferreiro | a6ea10e5 | 2020-10-27 12:21:25 | [diff] [blame] | 234 | info.filesystem_id = std::string(); |
Henrique Ferreiro | 0bb413bf | 2020-09-17 13:37:54 | [diff] [blame] | 235 | result.file_system_files.push_back(std::move(info)); |
| 236 | break; |
| 237 | } |
| 238 | } |
| 239 | } |
| 240 | return result; |
| 241 | } |
| 242 | |
| 243 | } // namespace content |