blob: 7aef20258df41bcb71fbabc853c6c37d1e551a30 [file] [log] [blame]
Henrique Ferreiro0bb413bf2020-09-17 13:37:541// 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 Ferreiroa6ea10e52020-10-27 12:21:2511#include "base/check.h"
Ken Rockotc73e50a72020-10-27 00:32:2312#include "base/containers/span.h"
Henrique Ferreiro0bb413bf2020-09-17 13:37:5413#include "base/files/file_path.h"
Henrique Ferreiroa6ea10e52020-10-27 12:21:2514#include "base/optional.h"
Henrique Ferreiro0bb413bf2020-09-17 13:37:5415#include "base/strings/utf_string_conversions.h"
Yuta Hijikata035083112020-11-11 07:02:3316#include "build/chromeos_buildflags.h"
Austin Sullivan559bb382021-01-26 00:52:4317#include "content/browser/file_system_access/file_system_access_manager_impl.h"
Henrique Ferreiro0bb413bf2020-09-17 13:37:5418#include "mojo/public/cpp/bindings/pending_remote.h"
19#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
Marijn Kruisselbrinkc1000472020-10-01 22:19:5420#include "storage/browser/file_system/external_mount_points.h"
Austin Sullivand35c33462021-01-06 21:16:3221#include "third_party/blink/public/mojom/file_system_access/file_system_access_drag_drop_token.mojom.h"
Henrique Ferreiro0bb413bf2020-09-17 13:37:5422#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
27namespace content {
28
Marijn Kruisselbrinkc1000472020-10-01 22:19:5429namespace {
30
31// On Chrome OS paths that exist on an external mount point need to be treated
Austin Sullivan559bb382021-01-26 00:52:4332// differently to make sure the File System Access code accesses these paths via
Marijn Kruisselbrinkc1000472020-10-01 22:19:5433// the correct file system backend. This method checks if this is the case, and
Austin Sullivan559bb382021-01-26 00:52:4334// updates `entry_path` to the path that should be used by the File System
35// Access implementation.
Austin Sullivanafefb722021-01-14 01:26:3936content::FileSystemAccessEntryFactory::PathType MaybeRemapPath(
Marijn Kruisselbrinkc1000472020-10-01 22:19:5437 base::FilePath* entry_path) {
Yuta Hijikata035083112020-11-11 07:02:3338#if BUILDFLAG(IS_CHROMEOS_ASH)
Marijn Kruisselbrinkc1000472020-10-01 22:19:5439 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 Sullivanafefb722021-01-14 01:26:3944 return content::FileSystemAccessEntryFactory::PathType::kExternal;
Marijn Kruisselbrinkc1000472020-10-01 22:19:5445 }
46#endif
Austin Sullivanafefb722021-01-14 01:26:3947 return content::FileSystemAccessEntryFactory::PathType::kLocal;
Marijn Kruisselbrinkc1000472020-10-01 22:19:5448}
49
50} // namespace
51
Henrique Ferreiro0bb413bf2020-09-17 13:37:5452blink::mojom::DragDataPtr DropDataToDragData(
53 const DropData& drop_data,
Austin Sullivan559bb382021-01-26 00:52:4354 FileSystemAccessManagerImpl* file_system_access_manager,
Henrique Ferreiro0bb413bf2020-09-17 13:37:5455 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 Sullivand35c33462021-01-06 21:16:3286 mojo::PendingRemote<blink::mojom::FileSystemAccessDragDropToken>
Henrique Ferreiro0bb413bf2020-09-17 13:37:5487 pending_token;
Marijn Kruisselbrinkc1000472020-10-01 22:19:5488 base::FilePath entry_path = file.path;
Austin Sullivan559bb382021-01-26 00:52:4389 FileSystemAccessManagerImpl::PathType path_type =
Marijn Kruisselbrinkc1000472020-10-01 22:19:5490 MaybeRemapPath(&entry_path);
Austin Sullivan559bb382021-01-26 00:52:4391 file_system_access_manager->CreateFileSystemAccessDragDropToken(
Marijn Kruisselbrinkc1000472020-10-01 22:19:5492 path_type, entry_path, child_id,
93 pending_token.InitWithNewPipeAndPassReceiver());
Austin Sullivand35c33462021-01-06 21:16:3294 item->file_system_access_token = std::move(pending_token);
Marijn Kruisselbrinkc1000472020-10-01 22:19:5495
Henrique Ferreiro0bb413bf2020-09-17 13:37:5496 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 Ferreiroa6ea10e52020-10-27 12:21:25115 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 Ferreiro0bb413bf2020-09-17 13:37:54127}
128
Dave Tapuskad2a55202020-10-27 17:08:11129blink::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 Ferreiro0bb413bf2020-09-17 13:37:54174DropData DragDataToDropData(const blink::mojom::DragData& drag_data) {
Henrique Ferreiroa6ea10e52020-10-27 12:21:25175 // This field should be empty when dragging from the renderer.
176 DCHECK(!drag_data.file_system_id);
Henrique Ferreiro0bb413bf2020-09-17 13:37:54177
Henrique Ferreiroa6ea10e52020-10-27 12:21:25178 DropData result;
Henrique Ferreiro0bb413bf2020-09-17 13:37:54179 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 Rockotc73e50a72020-10-27 00:32:23208 base::span<const uint8_t> contents = base::make_span(binary_item->data);
Henrique Ferreiro35b04f22020-10-05 09:18:39209 result.file_contents.assign(contents.begin(), contents.end());
Henrique Ferreiro0bb413bf2020-09-17 13:37:54210 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 Ferreiroa6ea10e52020-10-27 12:21:25228 // This field should be empty when dragging from the renderer.
229 DCHECK(!file_system_file_item->file_system_id);
230
Henrique Ferreiro0bb413bf2020-09-17 13:37:54231 DropData::FileSystemFileInfo info;
232 info.url = file_system_file_item->url;
233 info.size = file_system_file_item->size;
Henrique Ferreiroa6ea10e52020-10-27 12:21:25234 info.filesystem_id = std::string();
Henrique Ferreiro0bb413bf2020-09-17 13:37:54235 result.file_system_files.push_back(std::move(info));
236 break;
237 }
238 }
239 }
240 return result;
241}
242
243} // namespace content