blob: bb04d0512a413d0fc9867f090b0a013e3a2e63d2 [file] [log] [blame]
// Copyright 2021 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/apps/app_service/intent_util.h"
#include <string>
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/web_applications/components/web_app_id.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/services/app_service/public/cpp/intent_util.h"
#include "content/public/test/browser_test.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "url/gurl.h"
using apps::mojom::Condition;
using apps::mojom::ConditionType;
using apps::mojom::IntentFilterPtr;
using apps::mojom::PatternMatchType;
namespace apps_util {
namespace {
void CheckUrlScopeFilter(const IntentFilterPtr& intent_filter,
const GURL& url,
const GURL& different_url) {
EXPECT_FALSE(intent_filter->activity_name.has_value());
EXPECT_FALSE(intent_filter->activity_label.has_value());
ASSERT_EQ(intent_filter->conditions.size(), 4U);
{
const Condition& condition = *intent_filter->conditions[0];
EXPECT_EQ(condition.condition_type, ConditionType::kAction);
ASSERT_EQ(condition.condition_values.size(), 1U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kNone);
EXPECT_EQ(condition.condition_values[0]->value, "view");
}
{
const Condition& condition = *intent_filter->conditions[1];
EXPECT_EQ(condition.condition_type, ConditionType::kScheme);
ASSERT_EQ(condition.condition_values.size(), 1U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kNone);
EXPECT_EQ(condition.condition_values[0]->value, url.scheme());
}
{
const Condition& condition = *intent_filter->conditions[2];
EXPECT_EQ(condition.condition_type, ConditionType::kHost);
ASSERT_EQ(condition.condition_values.size(), 1U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kNone);
EXPECT_EQ(condition.condition_values[0]->value, url.host());
}
{
const Condition& condition = *intent_filter->conditions[3];
EXPECT_EQ(condition.condition_type, ConditionType::kPattern);
ASSERT_EQ(condition.condition_values.size(), 1U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kPrefix);
EXPECT_EQ(condition.condition_values[0]->value, url.path());
}
EXPECT_TRUE(apps_util::IntentMatchesFilter(
apps_util::CreateIntentFromUrl(url), intent_filter));
EXPECT_FALSE(apps_util::IntentMatchesFilter(
apps_util::CreateIntentFromUrl(different_url), intent_filter));
}
void CheckShareTextFilter(const IntentFilterPtr& intent_filter) {
EXPECT_FALSE(intent_filter->activity_name.has_value());
EXPECT_FALSE(intent_filter->activity_label.has_value());
ASSERT_EQ(intent_filter->conditions.size(), 2U);
{
const Condition& condition = *intent_filter->conditions[0];
EXPECT_EQ(condition.condition_type, ConditionType::kAction);
ASSERT_EQ(condition.condition_values.size(), 1U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kNone);
EXPECT_EQ(condition.condition_values[0]->value, "send");
}
const Condition& condition = *intent_filter->conditions[1];
EXPECT_EQ(condition.condition_type, ConditionType::kMimeType);
ASSERT_EQ(condition.condition_values.size(), 1U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kMimeType);
EXPECT_EQ(condition.condition_values[0]->value, "text/plain");
EXPECT_TRUE(apps_util::IntentMatchesFilter(
apps_util::CreateShareIntentFromText("text", "title"), intent_filter));
std::vector<GURL> filesystem_urls(1U);
std::vector<std::string> mime_types(1U, "audio/mp3");
EXPECT_FALSE(apps_util::IntentMatchesFilter(
apps_util::CreateShareIntentFromFiles(filesystem_urls, mime_types),
intent_filter));
}
void CheckShareFileFilter(const IntentFilterPtr& intent_filter,
const std::vector<std::string>& filter_types,
const std::vector<std::string>& accepted_types,
const std::vector<std::string>& rejected_types) {
EXPECT_FALSE(intent_filter->activity_name.has_value());
EXPECT_FALSE(intent_filter->activity_label.has_value());
ASSERT_EQ(intent_filter->conditions.size(), filter_types.empty() ? 1U : 2U);
{
const Condition& condition = *intent_filter->conditions[0];
EXPECT_EQ(condition.condition_type, ConditionType::kAction);
ASSERT_EQ(condition.condition_values.size(), 2U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kNone);
EXPECT_EQ(condition.condition_values[0]->value, "send");
EXPECT_EQ(condition.condition_values[1]->match_type,
PatternMatchType::kNone);
EXPECT_EQ(condition.condition_values[1]->value, "send_multiple");
}
if (!filter_types.empty()) {
const Condition& condition = *intent_filter->conditions[1];
EXPECT_EQ(condition.condition_type, ConditionType::kMimeType);
ASSERT_EQ(condition.condition_values.size(), filter_types.size());
for (unsigned i = 0; i < filter_types.size(); ++i) {
EXPECT_EQ(condition.condition_values[i]->match_type,
PatternMatchType::kMimeType);
EXPECT_EQ(condition.condition_values[i]->value, filter_types[i]);
}
}
for (const std::string& accepted_type : accepted_types) {
{
std::vector<GURL> filesystem_urls(1U);
std::vector<std::string> mime_types(1U, accepted_type);
EXPECT_TRUE(apps_util::IntentMatchesFilter(
apps_util::CreateShareIntentFromFiles(filesystem_urls, mime_types),
intent_filter));
}
{
std::vector<GURL> filesystem_urls(3U);
std::vector<std::string> mime_types(3U, accepted_type);
EXPECT_TRUE(apps_util::IntentMatchesFilter(
apps_util::CreateShareIntentFromFiles(filesystem_urls, mime_types),
intent_filter));
}
}
for (const std::string& rejected_type : rejected_types) {
std::vector<GURL> filesystem_urls(1U);
std::vector<std::string> mime_types(1U, rejected_type);
EXPECT_FALSE(apps_util::IntentMatchesFilter(
apps_util::CreateShareIntentFromFiles(filesystem_urls, mime_types),
intent_filter));
}
}
} // namespace
class WebAppsUtilsBrowserTest : public InProcessBrowserTest {
public:
WebAppsUtilsBrowserTest() {
feature_list_.InitAndEnableFeature(features::kIntentHandlingSharing);
}
~WebAppsUtilsBrowserTest() override = default;
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(WebAppsUtilsBrowserTest, PopulateIntentFilters) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url(
embedded_test_server()->GetURL("/web_share_target/charts.html"));
std::vector<IntentFilterPtr> target;
{
const web_app::WebAppRegistrar* registrar =
web_app::WebAppProvider::Get(browser()->profile())
->registrar()
.AsWebAppRegistrar();
const web_app::AppId app_id =
web_app::InstallWebAppFromManifest(browser(), app_url);
const web_app::WebApp* web_app = registrar->GetAppById(app_id);
ASSERT_TRUE(web_app);
PopulateWebAppIntentFilters(*web_app, target);
}
ASSERT_EQ(target.size(), 3U);
CheckUrlScopeFilter(target[0], app_url.GetWithoutFilename(),
/*different_url=*/GURL("file:///"));
CheckShareTextFilter(target[1]);
const std::vector<std::string> filter_types(
{"text/*", "image/svg+xml", "*/*"});
const std::vector<std::string> accepted_types(
{"text/plain", "image/svg+xml", "video/webm"});
const std::vector<std::string> rejected_types; // No types are rejected.
CheckShareFileFilter(target[2], filter_types, accepted_types, rejected_types);
}
IN_PROC_BROWSER_TEST_F(WebAppsUtilsBrowserTest, PartialWild) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url(
embedded_test_server()->GetURL("/web_share_target/partial-wild.html"));
std::vector<IntentFilterPtr> target;
{
const web_app::WebAppRegistrar* registrar =
web_app::WebAppProvider::Get(browser()->profile())
->registrar()
.AsWebAppRegistrar();
const web_app::AppId app_id =
web_app::InstallWebAppFromManifest(browser(), app_url);
const web_app::WebApp* web_app = registrar->GetAppById(app_id);
ASSERT_TRUE(web_app);
PopulateWebAppIntentFilters(*web_app, target);
}
ASSERT_EQ(target.size(), 2U);
CheckUrlScopeFilter(target[0], app_url.GetWithoutFilename(),
/*different_url=*/GURL("file:///"));
const std::vector<std::string> filter_types({"image/*"});
const std::vector<std::string> accepted_types({"image/png", "image/svg+xml"});
const std::vector<std::string> rejected_types(
{"application/vnd.android.package-archive", "text/plain"});
CheckShareFileFilter(target[1], filter_types, accepted_types, rejected_types);
}
IN_PROC_BROWSER_TEST_F(WebAppsUtilsBrowserTest, ShareTargetWithoutFiles) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url(
embedded_test_server()->GetURL("/web_share_target/poster.html"));
std::vector<IntentFilterPtr> target;
{
const web_app::WebAppRegistrar* registrar =
web_app::WebAppProvider::Get(browser()->profile())
->registrar()
.AsWebAppRegistrar();
const web_app::AppId app_id =
web_app::InstallWebAppFromManifest(browser(), app_url);
const web_app::WebApp* web_app = registrar->GetAppById(app_id);
ASSERT_TRUE(web_app);
PopulateWebAppIntentFilters(*web_app, target);
}
ASSERT_EQ(target.size(), 2U);
CheckUrlScopeFilter(target[0], app_url.GetWithoutFilename(),
/*different_url=*/GURL("file:///"));
CheckShareTextFilter(target[1]);
}
} // namespace apps_util