Commit f6a6b9ae authored by Jay Harris's avatar Jay Harris Committed by Commit Bot

Creates a system for pushing LaunchParams into the renderer.

This CL is part of the work on file-handling:
https://github.com/WICG/file-handling/blob/master/explainer.md

After this CL, websites will be able to access files (if any) that
they were launched with.

This feature is hidden behind two experimental flags:
NativeFileSystemAPI and FileHandlingAPI.

Bug: 829689
Change-Id: I503afebb7d5ee00eff3bc032245c57966ca34872
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1672608
Commit-Queue: Jay Harris <harrisjay@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarAlexey Baskakov <loyso@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#680279}
parent 3878c8d0
......@@ -3463,6 +3463,8 @@ jumbo_split_static_library("browser") {
"usb/web_usb_chooser_desktop.h",
"usb/web_usb_detector.cc",
"usb/web_usb_detector.h",
"web_launch/web_launch_files_helper.cc",
"web_launch/web_launch_files_helper.h",
]
deps += [
":theme_properties",
......
......@@ -6,6 +6,7 @@
#define CHROME_BROWSER_APPS_APP_SERVICE_APP_LAUNCH_PARAMS_H_
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/files/file_path.h"
......@@ -79,6 +80,10 @@ struct AppLaunchParams {
// The frame that initiated the open. May be null. If set, the new app will
// have |opener| as its window.opener.
content::RenderFrameHost* opener;
// The files the application was launched with. Empty if the application was
// not launched with files.
std::vector<base::FilePath> launch_files;
};
#endif // CHROME_BROWSER_APPS_APP_SERVICE_APP_LAUNCH_PARAMS_H_
......@@ -432,6 +432,7 @@ bool ExecuteFileTask(Profile* profile,
WindowOpenDisposition::NEW_FOREGROUND_TAB,
extensions::AppLaunchSource::kSourceFileHandler);
params.override_url = GURL(task.action_id);
params.launch_files = std::move(paths);
OpenApplication(params);
}
if (!done.is_null())
......
......@@ -35,6 +35,7 @@
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/web_applications/components/web_app_helpers.h"
#include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
#include "chrome/browser/web_launch/web_launch_files_helper.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/common/url_constants.h"
......@@ -427,6 +428,10 @@ WebContents* ShowApplicationWindow(const AppLaunchParams& params,
// TODO(jcampan): http://crbug.com/8123 we should not need to set the initial
// focus explicitly.
web_contents->SetInitialFocus();
web_launch::WebLaunchFilesHelper::SetLaunchPaths(web_contents, url,
params.launch_files);
return web_contents;
}
......
......@@ -874,48 +874,83 @@ class HostedAppFileHandlingTest : public HostedAppTest {
{});
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
base::FilePath NewTestFilePath() {
// CreateTemporaryFile blocks, temporarily allow blocking.
base::ScopedAllowBlockingForTesting allow_blocking;
base::FilePath test_file_path;
base::CreateTemporaryFile(&test_file_path);
return test_file_path;
}
std::string InstallFileHandlingPWA() {
DCHECK_EQ(web_app_info_.app_url, GURL());
GURL url = GetSecureAppURL();
web_app_info_.app_url = url;
web_app_info_.scope = url.GetWithoutFilename();
web_app_info_.title = base::ASCIIToUTF16("A Hosted App");
web_app_info_.file_handler = blink::Manifest::FileHandler();
web_app_info_.file_handler->action =
https_server()->GetURL("app.com", "/ssl/blank_page.html");
{
std::vector<blink::Manifest::FileFilter> filters;
blink::Manifest::FileFilter text = {
base::ASCIIToUTF16("text"),
{base::ASCIIToUTF16(".txt"), base::ASCIIToUTF16("text/*")}};
filters.push_back(text);
web_app_info_.file_handler->files = std::move(filters);
}
IN_PROC_BROWSER_TEST_P(HostedAppFileHandlingTest, PWAsCanViewLaunchParams) {
ASSERT_TRUE(https_server()->Start());
app_ = InstallBookmarkApp(web_app_info_);
return app_->id();
}
GURL url = GetSecureAppURL();
content::WebContents* LaunchWithFiles(
const std::string& app_id,
const std::vector<base::FilePath>& files) {
AppLaunchParams params(browser()->profile(), app_id,
extensions::LaunchContainer::kLaunchContainerWindow,
WindowOpenDisposition::NEW_WINDOW,
extensions::AppLaunchSource::kSourceFileHandler);
params.launch_files = files;
WebApplicationInfo web_app_info;
web_app_info.app_url = url;
web_app_info.scope = url.GetWithoutFilename();
web_app_info.title = base::ASCIIToUTF16("A Hosted App");
web_app_info.file_handler = blink::Manifest::FileHandler();
web_app_info.file_handler->action =
GURL(https_server()->GetURL("app.com", "/ssl/blank_page.html"));
content::TestNavigationObserver navigation_observer(
web_app_info_.file_handler->action);
navigation_observer.StartWatchingNewWebContents();
{
std::vector<blink::Manifest::FileFilter> filters;
blink::Manifest::FileFilter text = {
base::ASCIIToUTF16("text"),
{base::ASCIIToUTF16(".txt"), base::ASCIIToUTF16("text/*")}};
filters.push_back(text);
web_app_info.file_handler->files = std::move(filters);
content::WebContents* web_contents =
OpenApplicationWindow(params, web_app_info_.file_handler->action);
navigation_observer.Wait();
return web_contents;
}
const extensions::Extension* app = InstallBookmarkApp(web_app_info);
private:
base::test::ScopedFeatureList scoped_feature_list_;
WebApplicationInfo web_app_info_;
};
IN_PROC_BROWSER_TEST_P(HostedAppFileHandlingTest, PWAsCanViewLaunchParams) {
ASSERT_TRUE(https_server()->Start());
AppLaunchParams params(browser()->profile(), app->id(),
extensions::LaunchContainer::kLaunchContainerWindow,
WindowOpenDisposition::NEW_WINDOW,
extensions::AppLaunchSource::kSourceFileHandler);
const std::string app_id = InstallFileHandlingPWA();
content::WebContents* web_contents = LaunchWithFiles(app_id, {});
EXPECT_EQ(0, content::EvalJs(web_contents, "launchParams.files.length"));
}
content::TestNavigationObserver navigation_observer(
web_app_info.file_handler->action);
navigation_observer.StartWatchingNewWebContents();
IN_PROC_BROWSER_TEST_P(HostedAppFileHandlingTest,
PWAsCanReceiveFileLaunchParams) {
ASSERT_TRUE(https_server()->Start());
const std::string app_id = InstallFileHandlingPWA();
base::FilePath test_file_path = NewTestFilePath();
content::WebContents* web_contents =
OpenApplicationWindow(params, web_app_info.file_handler->action);
navigation_observer.Wait();
LaunchWithFiles(app_id, {test_file_path});
EXPECT_EQ(0, content::EvalJs(web_contents, "launchParams.files.length"));
EXPECT_EQ(1, content::EvalJs(web_contents, "launchParams.files.length"));
EXPECT_EQ(test_file_path.BaseName().value(),
content::EvalJs(web_contents, "launchParams.files[0].name"));
}
#if !defined(OS_ANDROID)
......
file://third_party/blink/renderer/modules/launch/OWNERS
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/web_launch/web_launch_files_helper.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_user_data.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom.h"
#include "url/origin.h"
namespace {
// Converts |paths| to |NativeFileSystemEntries|, which can be manipulated by
// |context|. Must be called on IO thread.
std::vector<blink::mojom::NativeFileSystemEntryPtr> GetEntries(
scoped_refptr<content::NativeFileSystemEntryFactory> entry_factory,
content::NativeFileSystemEntryFactory::BindingContext context,
std::vector<base::FilePath> paths) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(entry_factory);
std::vector<blink::mojom::NativeFileSystemEntryPtr> launch_entries;
launch_entries.reserve(paths.size());
for (const auto& path : paths) {
launch_entries.push_back(
entry_factory->CreateFileEntryFromPath(context, path));
}
return launch_entries;
}
} // namespace
namespace web_launch {
WEB_CONTENTS_USER_DATA_KEY_IMPL(WebLaunchFilesHelper)
// static
void WebLaunchFilesHelper::SetLaunchPaths(
content::WebContents* web_contents,
const GURL& launch_url,
std::vector<base::FilePath> launch_paths) {
if (launch_paths.size() == 0)
return;
web_contents->SetUserData(
UserDataKey(), std::make_unique<WebLaunchFilesHelper>(
web_contents, launch_url, std::move(launch_paths)));
}
void WebLaunchFilesHelper::DidFinishNavigation(
content::NavigationHandle* handle) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Currently, launch data is only sent for the main frame.
if (!handle->IsInMainFrame())
return;
MaybeSendLaunchEntries();
}
WebLaunchFilesHelper::WebLaunchFilesHelper(
content::WebContents* web_contents,
const GURL& launch_url,
std::vector<base::FilePath> launch_paths)
: content::WebContentsObserver(web_contents), launch_url_(launch_url) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(launch_paths.size());
scoped_refptr<content::NativeFileSystemEntryFactory> entry_factory =
web_contents->GetMainFrame()
->GetProcess()
->GetStoragePartition()
->GetNativeFileSystemEntryFactory();
content::NativeFileSystemEntryFactory::BindingContext context(
url::Origin::Create(launch_url),
web_contents->GetMainFrame()->GetProcess()->GetID(),
web_contents->GetMainFrame()->GetRoutingID());
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&GetEntries, std::move(entry_factory), std::move(context),
std::move(launch_paths)),
base::BindOnce(&WebLaunchFilesHelper::SetLaunchEntries,
weak_ptr_factory.GetWeakPtr()));
}
WebLaunchFilesHelper::~WebLaunchFilesHelper() = default;
void WebLaunchFilesHelper::SetLaunchEntries(
std::vector<blink::mojom::NativeFileSystemEntryPtr> launch_entries) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
launch_entries_ = std::move(launch_entries);
MaybeSendLaunchEntries();
}
void WebLaunchFilesHelper::MaybeSendLaunchEntries() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (launch_entries_.size() == 0)
return;
if (launch_url_ != web_contents()->GetLastCommittedURL())
return;
blink::mojom::WebLaunchServiceAssociatedPtr launch_service;
web_contents()->GetMainFrame()->GetRemoteAssociatedInterfaces()->GetInterface(
&launch_service);
DCHECK(launch_service);
launch_service->SetLaunchFiles(std::move(launch_entries_));
// LaunchParams are sent, clean up.
web_contents()->RemoveUserData(UserDataKey());
}
} // namespace web_launch
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_WEB_LAUNCH_WEB_LAUNCH_FILES_HELPER_H_
#define CHROME_BROWSER_WEB_LAUNCH_WEB_LAUNCH_FILES_HELPER_H_
#include <vector>
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/native_file_system_entry_factory.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-forward.h"
#include "third_party/blink/public/mojom/web_launch/web_launch.mojom.h"
#include "url/gurl.h"
namespace content {
class WebContents;
class NavigationHandle;
} // namespace content
namespace web_launch {
// A helper for sending launch paths to the renderer process.
// Launch files cannot be sent immediately for two reasons:
// 1) Creating NativeFileSystemFileEntries has to happen on the IO thread.
// 2) The data is stored on a document for |launch_url_|, which is not created
// until |launch_url_| is committed.
//
// Note: The lifetime of this class is tied to the WebContents it is attached
// to. However, in general it will be destroyed before the WebContents, when the
// helper sends the NativeFileSystemEntries to the renderer.
class WebLaunchFilesHelper
: public content::WebContentsObserver,
public content::WebContentsUserData<WebLaunchFilesHelper> {
public:
WEB_CONTENTS_USER_DATA_KEY_DECL();
static void SetLaunchPaths(content::WebContents* web_contents,
const GURL& launch_url,
std::vector<base::FilePath> launch_paths);
WebLaunchFilesHelper(content::WebContents* web_contents,
const GURL& launch_url,
std::vector<base::FilePath> launch_paths);
~WebLaunchFilesHelper() override;
// content::WebContentsObserver:
void DidFinishNavigation(content::NavigationHandle* handle) override;
private:
// Callback which fires when launch entries have been created.
void SetLaunchEntries(
std::vector<blink::mojom::NativeFileSystemEntryPtr> launch_entries);
// Sends the launch entries to the renderer if they have been created and the
// renderer is ready to receive them.
void MaybeSendLaunchEntries();
// The entries causing the launch (may be empty).
std::vector<blink::mojom::NativeFileSystemEntryPtr> launch_entries_;
// The url the launch entries are for.
GURL launch_url_;
base::WeakPtrFactory<WebLaunchFilesHelper> weak_ptr_factory{this};
DISALLOW_COPY_AND_ASSIGN(WebLaunchFilesHelper);
};
} // namespace web_launch
#endif // CHROME_BROWSER_WEB_LAUNCH_WEB_LAUNCH_FILES_HELPER_H_
......@@ -71,6 +71,7 @@ const service_manager::Manifest& GetContentRendererManifest() {
"blink.mojom.MediaDevicesListener",
"blink.mojom.MediaStreamDeviceObserver",
"blink.mojom.TextSuggestionBackend",
"blink.mojom.WebLaunchService",
"content.mojom.FrameInputHandler",
"content.mojom.FullscreenVideoElementHandler",
"content.mojom.Widget", "viz.mojom.InputTargetClient"})
......
......@@ -128,6 +128,7 @@ mojom("mojom_platform") {
"user_agent/user_agent_metadata.mojom",
"v8_cache_options.mojom",
"wake_lock/wake_lock.mojom",
"web_launch/web_launch.mojom",
"webaudio/audio_context_manager.mojom",
"webdatabase/web_database.mojom",
"websockets/websocket_connector.mojom",
......
file://third_party/blink/renderer/modules/launch/OWNERS
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module blink.mojom;
import "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom";
import "url/mojom/url.mojom";
// Interface for getting the cause of page loads to blink. This service lives
// in blink and is used to implement the File Handling proposal:
// https://github.com/WICG/file-handling/blob/master/explainer.md
// TODO(harrisjay): Replace link to explainer with link to spec, when
// available.
//
// An instance of this service is tied to a LocalFrame.
interface WebLaunchService {
// Used to notify a frame that it was opened with |files|. This
// method is fire-and-forget.
SetLaunchFiles(array<NativeFileSystemEntry> files);
};
\ No newline at end of file
......@@ -10,6 +10,8 @@ blink_modules_sources("launch") {
"dom_window_launch_params.h",
"launch_params.cc",
"launch_params.h",
"web_launch_service_impl.cc",
"web_launch_service_impl.h",
]
deps = [
......
harrisjay@chromium.org
raymes@chromium.org
# TEAM: web-apps-platform-team@chromium.org
# COMPONENT: UI->Browser->WebAppInstalls
\ No newline at end of file
......@@ -24,6 +24,12 @@ Member<LaunchParams> DOMWindowLaunchParams::launchParams(
return FromState(&window)->launch_params_;
}
void DOMWindowLaunchParams::UpdateLaunchFiles(
LocalDOMWindow* window,
HeapVector<Member<NativeFileSystemHandle>> files) {
FromState(window)->launch_params_->SetFiles(std::move(files));
}
void DOMWindowLaunchParams::Trace(blink::Visitor* visitor) {
visitor->Trace(launch_params_);
Supplement<LocalDOMWindow>::Trace(visitor);
......
......@@ -33,6 +33,9 @@ class DOMWindowLaunchParams final
// IDL Interface.
static Member<LaunchParams> launchParams(LocalDOMWindow&);
static void UpdateLaunchFiles(LocalDOMWindow*,
HeapVector<Member<NativeFileSystemHandle>>);
void Trace(blink::Visitor*) override;
private:
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/launch/web_launch_service_impl.h"
#include <memory>
#include "mojo/public/cpp/bindings/strong_associated_binding.h"
#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/script/script.h"
#include "third_party/blink/renderer/modules/launch/dom_window_launch_params.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
namespace blink {
void WebLaunchServiceImpl::Create(
LocalFrame* frame,
mojom::blink::WebLaunchServiceAssociatedRequest request) {
DCHECK(frame);
mojo::MakeStrongAssociatedBinding(
std::make_unique<WebLaunchServiceImpl>(*frame->DomWindow()),
std::move(request));
}
WebLaunchServiceImpl::WebLaunchServiceImpl(LocalDOMWindow& window)
: window_(window) {}
WebLaunchServiceImpl::~WebLaunchServiceImpl() = default;
void WebLaunchServiceImpl::SetLaunchFiles(
WTF::Vector<mojom::blink::NativeFileSystemEntryPtr> entries) {
if (!window_)
return;
HeapVector<Member<NativeFileSystemHandle>> files;
for (auto& entry : entries) {
files.push_back(NativeFileSystemHandle::CreateFromMojoEntry(
std::move(entry), window_->GetExecutionContext()));
}
DOMWindowLaunchParams::UpdateLaunchFiles(window_, std::move(files));
}
} // namespace blink
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_WEB_LAUNCH_SERVICE_IMPL_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_WEB_LAUNCH_SERVICE_IMPL_H_
#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/web_launch/web_launch.mojom-blink.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
class LocalFrame;
class LocalDOMWindow;
// Implementation of WebLaunchService, to allow the renderer to receive launch
// parameters from the browser process.
class MODULES_EXPORT WebLaunchServiceImpl final
: public mojom::blink::WebLaunchService {
public:
static void Create(LocalFrame* frame,
mojom::blink::WebLaunchServiceAssociatedRequest);
explicit WebLaunchServiceImpl(LocalDOMWindow& frame);
~WebLaunchServiceImpl() override;
// blink::mojom::WebLaunchService:
void SetLaunchFiles(
WTF::Vector<mojom::blink::NativeFileSystemEntryPtr>) override;
private:
WeakPersistent<LocalDOMWindow> window_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_WEB_LAUNCH_SERVICE_IMPL_H_
......@@ -58,6 +58,7 @@
#include "third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h"
#include "third_party/blink/renderer/modules/installation/installation_service_impl.h"
#include "third_party/blink/renderer/modules/installedapp/installed_app_controller.h"
#include "third_party/blink/renderer/modules/launch/web_launch_service_impl.h"
#include "third_party/blink/renderer/modules/manifest/manifest_manager.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
#include "third_party/blink/renderer/modules/mediastream/user_media_client.h"
......@@ -162,6 +163,10 @@ void ModulesInitializer::InitLocalFrame(LocalFrame& frame) const {
frame.GetInterfaceRegistry()->AddInterface(WTF::BindRepeating(
&CopylessPasteServer::BindMojoRequest, WrapWeakPersistent(&frame)));
}
if (RuntimeEnabledFeatures::FileHandlingEnabled()) {
frame.GetInterfaceRegistry()->AddAssociatedInterface(WTF::BindRepeating(
&WebLaunchServiceImpl::Create, WrapWeakPersistent(&frame)));
}
frame.GetInterfaceRegistry()->AddInterface(WTF::BindRepeating(
&InstallationServiceImpl::Create, WrapWeakPersistent(&frame)));
// TODO(dominickn): This interface should be document-scoped rather than
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment