Commit 9c3e5490 authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Media Feeds] Add method to check URLs

Add method to check media feed items against
safesearch and store the result.

BUG=1066643

Change-Id: I9779c7fdde6916f47afd60f4d5efd379853f03cd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2135875Reviewed-by: default avatarNicolas Ouellet-Payeur <nicolaso@chromium.org>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#759276}
parent 719443f1
......@@ -6,13 +6,34 @@
#include "base/feature_list.h"
#include "chrome/browser/media/feeds/media_feeds_service_factory.h"
#include "chrome/browser/media/history/media_history_keyed_service.h"
#include "chrome/browser/media/history/media_history_keyed_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "components/safe_search_api/safe_search/safe_search_url_checker_client.h"
#include "components/safe_search_api/url_checker.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h"
#include "media/base/media_switches.h"
#include "url/gurl.h"
namespace media_feeds {
MediaFeedsService::MediaFeedsService(Profile* profile) {
namespace {
GURL Normalize(const GURL& url) {
GURL normalized_url = url;
GURL::Replacements replacements;
// Strip username, password, query, and ref.
replacements.ClearUsername();
replacements.ClearPassword();
replacements.ClearQuery();
replacements.ClearRef();
return url.ReplaceComponents(replacements);
}
} // namespace
MediaFeedsService::MediaFeedsService(Profile* profile) : profile_(profile) {
DCHECK(!profile->IsOffTheRecord());
}
......@@ -27,4 +48,147 @@ bool MediaFeedsService::IsEnabled() {
return base::FeatureList::IsEnabled(media::kMediaFeeds);
}
void MediaFeedsService::CheckItemsAgainstSafeSearch(
media_history::MediaHistoryKeyedService::PendingSafeSearchCheckList list) {
for (auto& check : list) {
if (!AddInflightSafeSearchCheck(check->id, check->urls))
continue;
for (auto& url : check->urls)
CheckForSafeSearch(check->id, url);
}
}
void MediaFeedsService::SetSafeSearchURLCheckerForTest(
std::unique_ptr<safe_search_api::URLChecker> safe_search_url_checker) {
safe_search_url_checker_ = std::move(safe_search_url_checker);
}
void MediaFeedsService::SetSafeSearchCompletionCallbackForTest(
base::OnceClosure callback) {
safe_search_completion_callback_ = std::move(callback);
}
bool MediaFeedsService::AddInflightSafeSearchCheck(const int64_t id,
const std::set<GURL>& urls) {
if (base::Contains(inflight_safe_search_checks_, id))
return false;
inflight_safe_search_checks_.emplace(
id, std::make_unique<InflightSafeSearchCheck>(urls));
return true;
}
void MediaFeedsService::CheckForSafeSearch(const int64_t id, const GURL& url) {
if (!safe_search_url_checker_) {
// TODO(https://crbug.com/1066643): Add a UI toggle to turn this feature on.
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("media_feeds_checker", R"(
semantics {
sender: "Media Feeds Safe Search Checker"
description:
"Media Feeds are feeds of personalized media recommendations "
"that are fetched from media websites and displayed to the user. "
"These feeds are discovered automatically on websites that embed "
"them. Chrome will then periodically fetch the feeds in the "
"background. This checker will check the media recommendations "
"against the Google SafeSearch API to ensure the recommendations "
"are safe and do not contain any inappropriate content."
trigger:
"Having a discovered feed that has not been fetched recently. "
"Feeds are discovered when the browser visits any webpage with a "
"feed link element in the header. Chrome will only fetch feeds "
"from a website that meets certain media heuristics. This is to "
"limit Media Feeds to only sites the user watches videos on."
data: "URL to be checked."
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: NO
setting:
"This feature is off by default and cannot be controlled in "
"settings."
chrome_policy {
SavingBrowserHistoryDisabled {
policy_options {mode: MANDATORY}
SavingBrowserHistoryDisabled: false
}
}
})");
safe_search_url_checker_ = std::make_unique<safe_search_api::URLChecker>(
std::make_unique<safe_search_api::SafeSearchURLCheckerClient>(
content::BrowserContext::GetDefaultStoragePartition(profile_)
->GetURLLoaderFactoryForBrowserProcess(),
traffic_annotation));
}
safe_search_url_checker_->CheckURL(
Normalize(url), base::BindOnce(&MediaFeedsService::OnCheckURLDone,
base::Unretained(this), id, url));
}
void MediaFeedsService::OnCheckURLDone(
const int64_t id,
const GURL& original_url,
const GURL& url,
safe_search_api::Classification classification,
bool uncertain) {
// Get the inflight safe search check data.
auto it = inflight_safe_search_checks_.find(id);
if (it == inflight_safe_search_checks_.end())
return;
// Remove the url we just checked from the pending list.
auto* check = it->second.get();
check->pending.erase(original_url);
if (uncertain) {
check->is_uncertain = true;
} else if (classification == safe_search_api::Classification::SAFE) {
check->is_safe = true;
} else if (classification == safe_search_api::Classification::UNSAFE) {
check->is_unsafe = true;
}
// If we have no more URLs to check or the result is unsafe then we should
// store now.
if (!(check->pending.empty() || check->is_unsafe))
return;
auto result = media_feeds::mojom::SafeSearchResult::kUnknown;
if (check->is_unsafe) {
result = media_feeds::mojom::SafeSearchResult::kUnsafe;
} else if (check->is_safe && !check->is_uncertain) {
result = media_feeds::mojom::SafeSearchResult::kSafe;
}
std::map<int64_t, media_feeds::mojom::SafeSearchResult> results;
results.emplace(id, result);
inflight_safe_search_checks_.erase(id);
auto* service =
media_history::MediaHistoryKeyedServiceFactory::GetForProfile(profile_);
DCHECK(service);
service->StoreMediaFeedItemSafeSearchResults(results);
MaybeCallCompletionCallback();
}
void MediaFeedsService::MaybeCallCompletionCallback() {
if (inflight_safe_search_checks_.empty() &&
safe_search_completion_callback_.has_value()) {
std::move(*safe_search_completion_callback_).Run();
safe_search_completion_callback_.reset();
}
}
MediaFeedsService::InflightSafeSearchCheck::InflightSafeSearchCheck(
const std::set<GURL>& urls)
: pending(urls) {}
MediaFeedsService::InflightSafeSearchCheck::~InflightSafeSearchCheck() =
default;
} // namespace media_feeds
......@@ -5,9 +5,20 @@
#ifndef CHROME_BROWSER_MEDIA_FEEDS_MEDIA_FEEDS_SERVICE_H_
#define CHROME_BROWSER_MEDIA_FEEDS_MEDIA_FEEDS_SERVICE_H_
#include <memory>
#include <set>
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "chrome/browser/media/history/media_history_keyed_service.h"
#include "components/keyed_service/core/keyed_service.h"
class Profile;
class GURL;
namespace safe_search_api {
enum class Classification;
class URLChecker;
} // namespace safe_search_api
namespace media_feeds {
......@@ -22,6 +33,54 @@ class MediaFeedsService : public KeyedService {
// Returns the instance attached to the given |profile|.
static MediaFeedsService* Get(Profile* profile);
// Checks the list of pending items against the Safe Search API and stores
// the result.
void CheckItemsAgainstSafeSearch(
media_history::MediaHistoryKeyedService::PendingSafeSearchCheckList list);
// Creates a SafeSearch URLChecker using a given URLLoaderFactory for testing.
void SetSafeSearchURLCheckerForTest(
std::unique_ptr<safe_search_api::URLChecker> safe_search_url_checker);
// Stores a callback to be called once we have completed all inflight checks.
void SetSafeSearchCompletionCallbackForTest(base::OnceClosure callback);
private:
friend class MediaFeedsServiceTest;
bool AddInflightSafeSearchCheck(const int64_t id, const std::set<GURL>& urls);
void CheckForSafeSearch(const int64_t id, const GURL& url);
void OnCheckURLDone(const int64_t id,
const GURL& original_url,
const GURL& url,
safe_search_api::Classification classification,
bool uncertain);
void MaybeCallCompletionCallback();
struct InflightSafeSearchCheck {
explicit InflightSafeSearchCheck(const std::set<GURL>& urls);
~InflightSafeSearchCheck();
InflightSafeSearchCheck(const InflightSafeSearchCheck&) = delete;
InflightSafeSearchCheck& operator=(const InflightSafeSearchCheck&) = delete;
std::set<GURL> pending;
bool is_safe = false;
bool is_unsafe = false;
bool is_uncertain = false;
};
std::map<int64_t, std::unique_ptr<InflightSafeSearchCheck>>
inflight_safe_search_checks_;
base::Optional<base::OnceClosure> safe_search_completion_callback_;
std::unique_ptr<safe_search_api::URLChecker> safe_search_url_checker_;
Profile* const profile_;
};
} // namespace media_feeds
......
......@@ -3694,6 +3694,7 @@ test("unit_tests") {
"//components/safe_browsing/core:features",
"//components/safe_browsing/core/db",
"//components/safe_browsing/core/db:test_database_manager",
"//components/safe_search_api:test_support",
"//components/schema_org/common:improved_mojom",
"//components/services/patch/content",
"//components/services/unzip/content",
......
......@@ -155,6 +155,7 @@ Refer to README.md for content description and update process.
<item id="logo_tracker" hash_code="36859107" type="0" deprecated="2018-12-07" content_hash_code="67588075" file_path=""/>
<item id="lookup_single_password_leak" hash_code="16927377" type="0" content_hash_code="12158296" os_list="linux,windows" file_path="components/password_manager/core/browser/leak_detection/leak_detection_request.cc"/>
<item id="media_feeds" hash_code="116778918" type="0" content_hash_code="48909601" os_list="linux,windows" file_path="chrome/browser/media/feeds/media_feeds_fetcher.cc"/>
<item id="media_feeds_checker" hash_code="107707089" type="0" content_hash_code="125348528" os_list="linux,windows" file_path="chrome/browser/media/feeds/media_feeds_service.cc"/>
<item id="media_router_global_media_controls_image" hash_code="95983790" type="0" content_hash_code="48851217" os_list="linux,windows" file_path="chrome/browser/ui/global_media_controls/cast_media_notification_item.cc"/>
<item id="metrics_report_ukm" hash_code="727478" type="0" content_hash_code="8746987" os_list="linux,windows" file_path="components/metrics/net/net_metrics_log_uploader.cc"/>
<item id="metrics_report_uma" hash_code="727528" type="0" content_hash_code="10176197" os_list="linux,windows" file_path="components/metrics/net/net_metrics_log_uploader.cc"/>
......
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