0

Revert "Topics: Sending Topics with image requests"

This reverts commit 072152ec38.

Reason for revert: See https://issues.chromium.org/u/1/issues/387306732

Original change's description:
> Topics: Sending Topics with image requests
>
> Send the Topics request header on image requests that specify the "browsingTopics" attribute.
>
> Use much of the existing plumbing work from the fetch() API. Adapt many
> of the tests for the fetch() API to also run for <img> attribute.
>
> PR: https://github.com/patcg-individual-drafts/topics/pull/357
>
> Bug: 382532794
>
> Change-Id: Id5975006a0c842df8765c49470c5f30bca7586c0
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6067268
> Commit-Queue: Abigail Katcoff <abigailkatcoff@chromium.org>
> Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
> Reviewed-by: Robert Ogden <robertogden@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1401483}

Bug: 382532794
Change-Id: Ia0403c388a639a0ff0a77dce9497108f2056aefd
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6138635
Owners-Override: Tim Sergeant <tsergeant@chromium.org>
Commit-Queue: David Yeung <dayeung@chromium.org>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Tim Sergeant <tsergeant@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1401650}
This commit is contained in:
David Yeung
2025-01-02 16:58:52 -08:00
committed by Chromium LUCI CQ
parent 679cb25d08
commit 4945b31056
26 changed files with 243 additions and 536 deletions

@@ -3524,7 +3524,6 @@ interface HTMLImageElement : HTMLElement
getter alt getter alt
getter attributionSrc getter attributionSrc
getter border getter border
getter browsingTopics
getter complete getter complete
getter crossOrigin getter crossOrigin
getter currentSrc getter currentSrc
@@ -3554,7 +3553,6 @@ interface HTMLImageElement : HTMLElement
setter alt setter alt
setter attributionSrc setter attributionSrc
setter border setter border
setter browsingTopics
setter crossOrigin setter crossOrigin
setter decoding setter decoding
setter fetchPriority setter fetchPriority
@@ -4616,7 +4614,6 @@ interface Image
getter alt getter alt
getter attributionSrc getter attributionSrc
getter border getter border
getter browsingTopics
getter complete getter complete
getter crossOrigin getter crossOrigin
getter currentSrc getter currentSrc
@@ -4646,7 +4643,6 @@ interface Image
setter alt setter alt
setter attributionSrc setter attributionSrc
setter border setter border
setter browsingTopics
setter crossOrigin setter crossOrigin
setter decoding setter decoding
setter fetchPriority setter fetchPriority

@@ -3522,7 +3522,6 @@ interface HTMLImageElement : HTMLElement
getter alt getter alt
getter attributionSrc getter attributionSrc
getter border getter border
getter browsingTopics
getter complete getter complete
getter crossOrigin getter crossOrigin
getter currentSrc getter currentSrc
@@ -3552,7 +3551,6 @@ interface HTMLImageElement : HTMLElement
setter alt setter alt
setter attributionSrc setter attributionSrc
setter border setter border
setter browsingTopics
setter crossOrigin setter crossOrigin
setter decoding setter decoding
setter fetchPriority setter fetchPriority
@@ -4614,7 +4612,6 @@ interface Image
getter alt getter alt
getter attributionSrc getter attributionSrc
getter border getter border
getter browsingTopics
getter complete getter complete
getter crossOrigin getter crossOrigin
getter currentSrc getter currentSrc
@@ -4644,7 +4641,6 @@ interface Image
setter alt setter alt
setter attributionSrc setter attributionSrc
setter border setter border
setter browsingTopics
setter crossOrigin setter crossOrigin
setter decoding setter decoding
setter fetchPriority setter fetchPriority

@@ -21,6 +21,7 @@
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h" #include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "components/browsing_topics/browsing_topics_service.h"
#include "components/browsing_topics/browsing_topics_service_impl.h" #include "components/browsing_topics/browsing_topics_service_impl.h"
#include "components/browsing_topics/epoch_topics.h" #include "components/browsing_topics/epoch_topics.h"
#include "components/browsing_topics/test_util.h" #include "components/browsing_topics/test_util.h"
@@ -622,105 +623,6 @@ class BrowsingTopicsBrowserTest : public BrowsingTopicsBrowserTestBase {
base::CallbackListSubscription subscription_; base::CallbackListSubscription subscription_;
}; };
class BrowsingTopicsSubresourceRequestTest
: public BrowsingTopicsBrowserTest,
public ::testing::WithParamInterface<bool> {
public:
// If true, test the fetch option. If false, test the img attribute.
bool TestFetch() { return GetParam(); }
std::string GetRelativePath() {
if (TestFetch()) {
return "/browsing_topics/page_with_custom_topics_header.html";
}
return "/browsing_topics/topics-writable-pixel.png";
}
std::string GetRedirectRelativePath() {
if (TestFetch()) {
return "/browsing_topics/page_with_custom_topics_header2.html";
}
return "/browsing_topics/topics-writable-pixel2.png";
}
bool ExecJsWithBrowsingTopicsTrue(GURL url) {
if (TestFetch()) {
return ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", url));
}
return ExecJs(web_contents()->GetPrimaryMainFrame(),
content::JsReplace(R"(
let img = document.createElement('img');
img.src = $1;
img.browsingTopics = true;
img.decode()
.then(() => {
document.body.appendChild(img);
})
)",
url.spec()));
}
bool ExecJSWithBrowsingTopicsFalse(GURL url) {
if (TestFetch()) {
return ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: false})", url));
}
return ExecJs(web_contents()->GetPrimaryMainFrame(),
content::JsReplace(R"(
let img = document.createElement('img');
img.src = $1;
img.browsingTopics = false;
img.decode()
.then(() => {
document.body.appendChild(img);
})
)",
url.spec()));
}
bool ExecJsWithMissingBrowsingTopicsAttribute(GURL url) {
if (TestFetch()) {
return ExecJs(web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1)", url));
}
return ExecJs(web_contents()->GetPrimaryMainFrame(),
content::JsReplace(R"(
let img = document.createElement('img');
img.src = $1;
img.decode()
.then(() => {
document.body.appendChild(img);
})
)",
url.spec()));
}
int GetBrowsingTopicsApiActionType(bool observe) {
if (TestFetch()) {
if (observe) {
return 3; // kObserveViaFetchLikeApi
}
return 2; // kGetViaFetchLikeApi;
}
if (observe) {
return 7; // kObserveViaImgAttributeApi
}
return 6; // kGetViaImgAttributeApi
}
};
INSTANTIATE_TEST_SUITE_P(All,
BrowsingTopicsSubresourceRequestTest,
::testing::Bool());
IN_PROC_BROWSER_TEST_F(BrowsingTopicsBrowserTest, HasBrowsingTopicsService) { IN_PROC_BROWSER_TEST_F(BrowsingTopicsBrowserTest, HasBrowsingTopicsService) {
EXPECT_TRUE(browsing_topics_service()); EXPECT_TRUE(browsing_topics_service());
} }
@@ -1261,19 +1163,24 @@ IN_PROC_BROWSER_TEST_F(
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), new_url)); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), new_url));
} }
IN_PROC_BROWSER_TEST_P( IN_PROC_BROWSER_TEST_F(
BrowsingTopicsSubresourceRequestTest, BrowsingTopicsBrowserTest,
SameOrigin_TopicsEligible_SendTopics_HasNoObserveResponse) { FetchSameOrigin_TopicsEligible_SendTopics_HasNoObserveResponse) {
GURL main_frame_url = GURL main_frame_url =
https_server_.GetURL("a.test", "/browsing_topics/empty_page.html"); https_server_.GetURL("a.test", "/browsing_topics/empty_page.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url)); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
GURL resource_url = https_server_.GetURL("a.test", GetRelativePath()); GURL fetch_url = https_server_.GetURL(
"a.test", "/browsing_topics/page_with_custom_topics_header.html");
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
EXPECT_TRUE(topics_header_value); EXPECT_TRUE(topics_header_value);
EXPECT_EQ(*topics_header_value, kExpectedHeaderValueForSiteA); EXPECT_EQ(*topics_header_value, kExpectedHeaderValueForSiteA);
@@ -1284,22 +1191,23 @@ IN_PROC_BROWSER_TEST_P(
EXPECT_EQ(api_usage_contexts.size(), 1u); EXPECT_EQ(api_usage_contexts.size(), 1u);
} }
IN_PROC_BROWSER_TEST_P(BrowsingTopicsSubresourceRequestTest, IN_PROC_BROWSER_TEST_F(BrowsingTopicsBrowserTest, FetchWithoutTopicsFlagSet) {
WithoutTopicsFlagSet) {
GURL main_frame_url = GURL main_frame_url =
https_server_.GetURL("b.test", "/browsing_topics/empty_page.html"); https_server_.GetURL("b.test", "/browsing_topics/empty_page.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url)); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
GURL resource_url = https_server_.GetURL("b.test", GetRelativePath()); GURL fetch_url = https_server_.GetURL(
"b.test", "/browsing_topics/page_with_custom_topics_header.html");
{ {
// Invoke fetch() or img without the `browsingTopics` flag. This request // Invoke fetch() without the `browsingTopics` flag. This request isn't
// isn't eligible for topics. // eligible for topics.
EXPECT_TRUE(ExecJs(web_contents()->GetPrimaryMainFrame(),
EXPECT_TRUE(ExecJsWithMissingBrowsingTopicsAttribute(resource_url)); content::JsReplace("fetch($1)", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
// Expect no topics header as the request did not specify // Expect no topics header as the request did not specify
// {browsingTopics: true}. // {browsingTopics: true}.
@@ -1307,12 +1215,15 @@ IN_PROC_BROWSER_TEST_P(BrowsingTopicsSubresourceRequestTest,
} }
{ {
// Invoke fetch() or img with the `browsingTopics` flag set to false. This // Invoke fetch() with the `browsingTopics` flag set to false. This request
// request isn't eligible for topics. // isn't eligible for topics.
EXPECT_TRUE(ExecJSWithBrowsingTopicsFalse(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: false})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
// Expect no topics header as the request did not specify // Expect no topics header as the request did not specify
// {browsingTopics: true}. // {browsingTopics: true}.
@@ -1320,21 +1231,25 @@ IN_PROC_BROWSER_TEST_P(BrowsingTopicsSubresourceRequestTest,
} }
} }
IN_PROC_BROWSER_TEST_P( IN_PROC_BROWSER_TEST_F(
BrowsingTopicsSubresourceRequestTest, BrowsingTopicsBrowserTest,
SameOrigin_TopicsEligible_SendNoTopic_HasNoObserveResponse) { FetchSameOrigin_TopicsEligible_SendNoTopic_HasNoObserveResponse) {
base::HistogramTester histogram_tester; base::HistogramTester histogram_tester;
GURL main_frame_url = GURL main_frame_url =
https_server_.GetURL("b.test", "/browsing_topics/empty_page.html"); https_server_.GetURL("b.test", "/browsing_topics/empty_page.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url)); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
GURL resource_url = https_server_.GetURL("b.test", GetRelativePath()); GURL fetch_url = https_server_.GetURL(
"b.test", "/browsing_topics/page_with_custom_topics_header.html");
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
// Expect an empty header value as "b.test" did not observe the candidate // Expect an empty header value as "b.test" did not observe the candidate
// topics. // topics.
@@ -1347,15 +1262,14 @@ IN_PROC_BROWSER_TEST_P(
content::GetBrowsingTopicsApiUsage(browsing_topics_site_data_manager()); content::GetBrowsingTopicsApiUsage(browsing_topics_site_data_manager());
EXPECT_EQ(api_usage_contexts.size(), 1u); EXPECT_EQ(api_usage_contexts.size(), 1u);
histogram_tester.ExpectUniqueSample( histogram_tester.ExpectUniqueSample(kBrowsingTopicsApiActionTypeHistogramId,
kBrowsingTopicsApiActionTypeHistogramId, 2 /*kGetViaFetchLikeApi*/,
GetBrowsingTopicsApiActionType(/*observe=*/false), /*expected_bucket_count=*/1);
/*expected_bucket_count=*/1);
} }
IN_PROC_BROWSER_TEST_P( IN_PROC_BROWSER_TEST_F(
BrowsingTopicsSubresourceRequestTest, BrowsingTopicsBrowserTest,
SameOrigin_TopicsEligible_SendNoTopic_HasObserveResponse) { FetchSameOrigin_TopicsEligible_SendNoTopic_HasObserveResponse) {
base::HistogramTester histogram_tester; base::HistogramTester histogram_tester;
GURL main_frame_url = GURL main_frame_url =
@@ -1368,11 +1282,15 @@ IN_PROC_BROWSER_TEST_P(
"Observe-Browsing-Topics: ?1")); "Observe-Browsing-Topics: ?1"));
replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", "")); replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", ""));
GURL resource_url = https_server_.GetURL( GURL fetch_url = https_server_.GetURL(
"b.test", net::test_server::GetFilePathWithReplacements(GetRelativePath(), "b.test", net::test_server::GetFilePathWithReplacements(
replacement)); "/browsing_topics/"
"page_with_custom_topics_header.html",
replacement));
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
// A new observation should have been recorded in addition to the pre-existing // A new observation should have been recorded in addition to the pre-existing
// one, as the response had the `Observe-Browsing-Topics: ?1` header and the // one, as the response had the `Observe-Browsing-Topics: ?1` header and the
@@ -1392,19 +1310,17 @@ IN_PROC_BROWSER_TEST_P(
// Expect a "get" event and an "observe" event respectively. // Expect a "get" event and an "observe" event respectively.
histogram_tester.ExpectTotalCount(kBrowsingTopicsApiActionTypeHistogramId, histogram_tester.ExpectTotalCount(kBrowsingTopicsApiActionTypeHistogramId,
/*expected_count=*/2); /*expected_count=*/2);
histogram_tester.ExpectBucketCount( histogram_tester.ExpectBucketCount(kBrowsingTopicsApiActionTypeHistogramId,
kBrowsingTopicsApiActionTypeHistogramId, 2 /*kGetViaFetchLikeApi*/,
GetBrowsingTopicsApiActionType(/*observe=*/false), /*expected_count=*/1);
/*expected_count=*/1); histogram_tester.ExpectBucketCount(kBrowsingTopicsApiActionTypeHistogramId,
histogram_tester.ExpectBucketCount( 3 /*kObserveViaFetchLikeApi*/,
kBrowsingTopicsApiActionTypeHistogramId, /*expected_count=*/1);
GetBrowsingTopicsApiActionType(/*observe=*/true),
/*expected_count=*/1);
} }
IN_PROC_BROWSER_TEST_P( IN_PROC_BROWSER_TEST_F(
BrowsingTopicsSubresourceRequestTest, BrowsingTopicsBrowserTest,
SameOrigin_TopicsNotEligibleDueToUserSettings_HasObserveResponse) { FetchSameOrigin_TopicsNotEligibleDueToUserSettings_HasObserveResponse) {
GURL main_frame_url = GURL main_frame_url =
https_server_.GetURL("a.test", "/browsing_topics/empty_page.html"); https_server_.GetURL("a.test", "/browsing_topics/empty_page.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url)); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
@@ -1415,17 +1331,22 @@ IN_PROC_BROWSER_TEST_P(
"Observe-Browsing-Topics: ?1")); "Observe-Browsing-Topics: ?1"));
replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", "")); replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", ""));
GURL resource_url = https_server_.GetURL( GURL fetch_url = https_server_.GetURL(
"a.test", net::test_server::GetFilePathWithReplacements(GetRelativePath(), "a.test", net::test_server::GetFilePathWithReplacements(
replacement)); "/browsing_topics/"
"page_with_custom_topics_header.html",
replacement));
CookieSettingsFactory::GetForProfile(browser()->profile()) CookieSettingsFactory::GetForProfile(browser()->profile())
->SetCookieSetting(resource_url, CONTENT_SETTING_BLOCK); ->SetCookieSetting(fetch_url, CONTENT_SETTING_BLOCK);
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
// When the request is ineligible for topics due to user settings, an empty // When the request is ineligible for topics due to user settings, an empty
// list of topics will be sent in the header. // list of topics will be sent in the header.
@@ -1439,9 +1360,9 @@ IN_PROC_BROWSER_TEST_P(
EXPECT_EQ(api_usage_contexts.size(), 1u); EXPECT_EQ(api_usage_contexts.size(), 1u);
} }
IN_PROC_BROWSER_TEST_P( IN_PROC_BROWSER_TEST_F(
BrowsingTopicsSubresourceRequestTest, BrowsingTopicsBrowserTest,
CrossOrigin_TopicsEligible_SendTopics_HasObserveResponse) { FetchCrossOrigin_TopicsEligible_SendTopics_HasObserveResponse) {
GURL main_frame_url = GURL main_frame_url =
https_server_.GetURL("b.test", "/browsing_topics/empty_page.html"); https_server_.GetURL("b.test", "/browsing_topics/empty_page.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url)); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
@@ -1452,14 +1373,19 @@ IN_PROC_BROWSER_TEST_P(
"Observe-Browsing-Topics: ?1")); "Observe-Browsing-Topics: ?1"));
replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", "")); replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", ""));
GURL resource_url = https_server_.GetURL( GURL fetch_url = https_server_.GetURL(
"a.test", net::test_server::GetFilePathWithReplacements(GetRelativePath(), "a.test", net::test_server::GetFilePathWithReplacements(
replacement)); "/browsing_topics/"
"page_with_custom_topics_header.html",
replacement));
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
EXPECT_TRUE(topics_header_value); EXPECT_TRUE(topics_header_value);
EXPECT_EQ(*topics_header_value, kExpectedHeaderValueForSiteB); EXPECT_EQ(*topics_header_value, kExpectedHeaderValueForSiteB);
@@ -1480,31 +1406,28 @@ IN_PROC_BROWSER_TEST_P(
EXPECT_EQ(api_usage_contexts[1].hashed_context_domain, HashedDomain(1)); EXPECT_EQ(api_usage_contexts[1].hashed_context_domain, HashedDomain(1));
} }
// On an insecure site (i.e. URL with http scheme), test a fetch or image // On an insecure site (i.e. URL with http scheme), test fetch request with
// request with the `browsingTopics` set to true. Expect it to throw an // the `browsingTopics` set to true. Expect it to throw an exception.
// exception. IN_PROC_BROWSER_TEST_F(
IN_PROC_BROWSER_TEST_P( BrowsingTopicsBrowserTest,
BrowsingTopicsSubresourceRequestTest, FetchCrossOrigin_TopicsNotEligibleDueToInsecureInitiatorContext) {
CrossOrigin_TopicsNotEligibleDueToInsecureInitiatorContext) {
GURL main_frame_url = embedded_test_server()->GetURL( GURL main_frame_url = embedded_test_server()->GetURL(
"b.test", "/browsing_topics/empty_page.html"); "b.test", "/browsing_topics/empty_page.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url)); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
GURL resource_url = https_server_.GetURL("a.test", GetRelativePath()); GURL fetch_url =
https_server_.GetURL("a.test", "/browsing_topics/empty_page.html");
if (TestFetch()) { content::EvalJsResult result = EvalJs(
content::EvalJsResult result = EvalJs( web_contents()->GetPrimaryMainFrame(),
web_contents()->GetPrimaryMainFrame(), content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url));
content::JsReplace("fetch($1, {browsingTopics: true})", resource_url));
EXPECT_THAT(result.error, EXPECT_THAT(result.error,
testing::HasSubstr("browsingTopics: Topics operations are only " testing::HasSubstr("browsingTopics: Topics operations are only "
"available in secure contexts.")); "available in secure contexts."));
} else {
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url));
}
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath("/browsing_topics/empty_page.html");
// Expect no topics header as the request was not eligible for topics due to // Expect no topics header as the request was not eligible for topics due to
// insecure initiator context. // insecure initiator context.
@@ -1513,9 +1436,9 @@ IN_PROC_BROWSER_TEST_P(
// Only allow topics from origin c.test, and test fetch requests to b.test and // Only allow topics from origin c.test, and test fetch requests to b.test and
// c.test to verify that only c.test gets them. // c.test to verify that only c.test gets them.
IN_PROC_BROWSER_TEST_P( IN_PROC_BROWSER_TEST_F(
BrowsingTopicsSubresourceRequestTest, BrowsingTopicsBrowserTest,
CrossOrigin_TopicsNotEligibleDueToPermissionsPolicyAgainstRequestOrigin) { FetchCrossOrigin_TopicsNotEligibleDueToPermissionsPolicyAgainstRequestOrigin) {
base::StringPairs allowed_origin_replacement; base::StringPairs allowed_origin_replacement;
allowed_origin_replacement.emplace_back( allowed_origin_replacement.emplace_back(
"{{ALLOWED_ORIGIN}}", https_server_.GetOrigin("c.test").Serialize()); "{{ALLOWED_ORIGIN}}", https_server_.GetOrigin("c.test").Serialize());
@@ -1531,12 +1454,15 @@ IN_PROC_BROWSER_TEST_P(
{ {
base::HistogramTester histogram_tester; base::HistogramTester histogram_tester;
GURL resource_url = https_server_.GetURL("a.test", GetRelativePath()); GURL fetch_url =
https_server_.GetURL("a.test", "/browsing_topics/empty_page.html");
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath("/browsing_topics/empty_page.html");
// No topics header was sent, as the permissions policy denied it. // No topics header was sent, as the permissions policy denied it.
EXPECT_FALSE(topics_header_value); EXPECT_FALSE(topics_header_value);
@@ -1551,29 +1477,31 @@ IN_PROC_BROWSER_TEST_P(
{ {
base::HistogramTester histogram_tester; base::HistogramTester histogram_tester;
GURL resource_url = https_server_.GetURL("c.test", GetRelativePath()); GURL fetch_url =
https_server_.GetURL("c.test", "/browsing_topics/empty_page.html");
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath("/browsing_topics/empty_page.html");
EXPECT_TRUE(topics_header_value); EXPECT_TRUE(topics_header_value);
histogram_tester.ExpectUniqueSample( histogram_tester.ExpectUniqueSample(kBrowsingTopicsApiActionTypeHistogramId,
kBrowsingTopicsApiActionTypeHistogramId, 2 /*kGetViaFetchLikeApi*/,
GetBrowsingTopicsApiActionType(/*observe=*/false), /*expected_bucket_count=*/1);
/*expected_bucket_count=*/1);
} }
} }
// On site b.test, test a fetch or image request to a.test that gets redirected // On site b.test, test fetch request to a.test that gets redirected to c.test.
// to c.test. The topics header should be calculated for them individually (i.e. // The topics header should be calculated for them individually (i.e. given that
// given that only a.test has observed the candidate topics for site b.test, the // only a.test has observed the candidate topics for site b.test, the request to
// request to a.test should have a non-empty topics header, while the redirected // a.test should have a non-empty topics header, while the redirected request to
// request to c.test should have an empty topics header.) // c.test should have an empty topics header.)
IN_PROC_BROWSER_TEST_P(BrowsingTopicsSubresourceRequestTest, IN_PROC_BROWSER_TEST_F(BrowsingTopicsBrowserTest,
CrossOriginWithRedirect) { FetchCrossOriginWithRedirect) {
base::HistogramTester histogram_tester; base::HistogramTester histogram_tester;
GURL main_frame_url = GURL main_frame_url =
@@ -1589,7 +1517,9 @@ IN_PROC_BROWSER_TEST_P(BrowsingTopicsSubresourceRequestTest,
GURL redirect_url = https_server_.GetURL( GURL redirect_url = https_server_.GetURL(
"c.test", net::test_server::GetFilePathWithReplacements( "c.test", net::test_server::GetFilePathWithReplacements(
GetRedirectRelativePath(), redirect_replacement)); "/browsing_topics/"
"page_with_custom_topics_header2.html",
redirect_replacement));
base::StringPairs replacement; base::StringPairs replacement;
replacement.emplace_back( replacement.emplace_back(
@@ -1599,21 +1529,27 @@ IN_PROC_BROWSER_TEST_P(BrowsingTopicsSubresourceRequestTest,
replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}",
"Location: " + redirect_url.spec())); "Location: " + redirect_url.spec()));
GURL resource_url = https_server_.GetURL( GURL fetch_url = https_server_.GetURL(
"a.test", net::test_server::GetFilePathWithReplacements(GetRelativePath(), "a.test", net::test_server::GetFilePathWithReplacements(
replacement)); "/browsing_topics/"
"page_with_custom_topics_header.html",
replacement));
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
{ {
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
EXPECT_TRUE(topics_header_value); EXPECT_TRUE(topics_header_value);
EXPECT_EQ(*topics_header_value, kExpectedHeaderValueForSiteB); EXPECT_EQ(*topics_header_value, kExpectedHeaderValueForSiteB);
} }
{ {
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRedirectRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header2.html");
EXPECT_TRUE(topics_header_value); EXPECT_TRUE(topics_header_value);
// An empty topics header value was sent, because "c.test" did not observe // An empty topics header value was sent, because "c.test" did not observe
@@ -1644,24 +1580,22 @@ IN_PROC_BROWSER_TEST_P(BrowsingTopicsSubresourceRequestTest,
// and the redirect respectively. // and the redirect respectively.
histogram_tester.ExpectTotalCount(kBrowsingTopicsApiActionTypeHistogramId, histogram_tester.ExpectTotalCount(kBrowsingTopicsApiActionTypeHistogramId,
/*expected_count=*/4); /*expected_count=*/4);
histogram_tester.ExpectBucketCount( histogram_tester.ExpectBucketCount(kBrowsingTopicsApiActionTypeHistogramId,
kBrowsingTopicsApiActionTypeHistogramId, 2 /*kGetViaFetchLikeApi*/,
GetBrowsingTopicsApiActionType(/*observe=*/false), /*expected_count=*/2);
/*expected_count=*/2); histogram_tester.ExpectBucketCount(kBrowsingTopicsApiActionTypeHistogramId,
histogram_tester.ExpectBucketCount( 3 /*kObserveViaFetchLikeApi*/,
kBrowsingTopicsApiActionTypeHistogramId, /*expected_count=*/2);
GetBrowsingTopicsApiActionType(/*observe=*/true),
/*expected_count=*/2);
} }
// On site b.test, test a fetch or image request to a.test that gets redirected // On site b.test, test fetch request to a.test that gets redirected to c.test.
// to c.test. The topics header eligibility should be checked for them // The topics header eligibility should be checked for them individually (i.e.
// individually (i.e. given that the declared policy on the page only allows // given that the declared policy on the page only allows origin c.test, the
// origin c.test, the request to a.test should not have the topics header, while // request to a.test should not have the topics header, while the redirected
// the redirected request to c.test should have the topics header.) // request to c.test should have the topics header.)
IN_PROC_BROWSER_TEST_P( IN_PROC_BROWSER_TEST_F(
BrowsingTopicsSubresourceRequestTest, BrowsingTopicsBrowserTest,
CrossOriginWithRedirect_InitialRequestTopicsNotEligibleDueToPermissionsPolicy) { FetchCrossOriginWithRedirect_InitialRequestTopicsNotEligibleDueToPermissionsPolicy) {
base::StringPairs allowed_origin_replacement; base::StringPairs allowed_origin_replacement;
allowed_origin_replacement.emplace_back( allowed_origin_replacement.emplace_back(
"{{ALLOWED_ORIGIN}}", https_server_.GetOrigin("c.test").Serialize()); "{{ALLOWED_ORIGIN}}", https_server_.GetOrigin("c.test").Serialize());
@@ -1682,7 +1616,9 @@ IN_PROC_BROWSER_TEST_P(
GURL redirect_url = https_server_.GetURL( GURL redirect_url = https_server_.GetURL(
"c.test", net::test_server::GetFilePathWithReplacements( "c.test", net::test_server::GetFilePathWithReplacements(
GetRedirectRelativePath(), redirect_replacement)); "/browsing_topics/"
"page_with_custom_topics_header2.html",
redirect_replacement));
base::StringPairs replacement; base::StringPairs replacement;
replacement.emplace_back( replacement.emplace_back(
@@ -1692,22 +1628,28 @@ IN_PROC_BROWSER_TEST_P(
replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}",
"Location: " + redirect_url.spec())); "Location: " + redirect_url.spec()));
GURL resource_url = https_server_.GetURL( GURL fetch_url = https_server_.GetURL(
"a.test", net::test_server::GetFilePathWithReplacements(GetRelativePath(), "a.test", net::test_server::GetFilePathWithReplacements(
replacement)); "/browsing_topics/"
"page_with_custom_topics_header.html",
replacement));
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
{ {
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
// No topics header was sent, as the permissions policy denied it. // No topics header was sent, as the permissions policy denied it.
EXPECT_FALSE(topics_header_value); EXPECT_FALSE(topics_header_value);
} }
{ {
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRedirectRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header2.html");
EXPECT_TRUE(topics_header_value); EXPECT_TRUE(topics_header_value);
// An empty topics header value was sent, as "c.test" did not observe the // An empty topics header value was sent, as "c.test" did not observe the
@@ -1797,71 +1739,6 @@ IN_PROC_BROWSER_TEST_F(BrowsingTopicsBrowserTest, UseCounter_Fetch) {
} }
} }
IN_PROC_BROWSER_TEST_F(BrowsingTopicsBrowserTest, UseCounter_Img) {
base::HistogramTester histogram_tester;
GURL main_frame_url =
https_server_.GetURL("a.test", "/browsing_topics/empty_page.html");
GURL img_url = https_server_.GetURL(
"a.test", "/browsing_topics/topics-writable-pixel.png");
{
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
// Request an image with `browsingTopics` set to false. Expect no
// `kTopicsAPIImg` use counter.
EXPECT_TRUE(ExecJs(web_contents()->GetPrimaryMainFrame(),
content::JsReplace(R"(
let img = document.createElement('img');
img.src = $1;
img.browsingTopics = false;
img.decode()
.then(() => {
document.body.appendChild(img);
})
)",
img_url.spec())));
// Navigate away to flush use counters.
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)));
histogram_tester.ExpectBucketCount("Blink.UseCounter.Features",
blink::mojom::WebFeature::kTopicsAPIImg,
0);
}
{
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
// Request an img with `browsingTopics` set to true. Expect one
// `kTopicsAPIImg` use counter.
EXPECT_TRUE(ExecJs(web_contents()->GetPrimaryMainFrame(),
content::JsReplace(R"(
let img = document.createElement('img');
img.src = $1;
img.browsingTopics = true;
img.decode()
.then(() => {
document.body.appendChild(img);
})
)",
img_url.spec())));
// Navigate away to flush use counters.
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)));
histogram_tester.ExpectBucketCount("Blink.UseCounter.Features",
blink::mojom::WebFeature::kTopicsAPIImg,
1);
histogram_tester.ExpectBucketCount("Blink.UseCounter.Features",
blink::mojom::WebFeature::kTopicsAPIAll,
1);
}
}
// For a page that contains a static <iframe> with a "browsingtopics" // For a page that contains a static <iframe> with a "browsingtopics"
// attribute, the iframe navigation request should be eligible for topics. // attribute, the iframe navigation request should be eligible for topics.
IN_PROC_BROWSER_TEST_F(BrowsingTopicsBrowserTest, IN_PROC_BROWSER_TEST_F(BrowsingTopicsBrowserTest,
@@ -2586,24 +2463,6 @@ class AttestationBrowsingTopicsBrowserTest : public BrowsingTopicsBrowserTest {
~AttestationBrowsingTopicsBrowserTest() override = default; ~AttestationBrowsingTopicsBrowserTest() override = default;
}; };
class AttestationSubresourceRequestTest
: public BrowsingTopicsSubresourceRequestTest {
public:
void SetUpOnMainThread() override {
// This test suite tests Privacy Sandbox Attestations related behaviors,
// turn off the setting that makes all APIs considered attested.
BrowsingTopicsBrowserTest::SetUpOnMainThread();
privacy_sandbox::PrivacySandboxAttestations::GetInstance()
->SetAllPrivacySandboxAttestedForTesting(false);
}
~AttestationSubresourceRequestTest() override = default;
};
INSTANTIATE_TEST_SUITE_P(All,
AttestationSubresourceRequestTest,
::testing::Bool());
// Site a.test is attested for Topics, so it should receive a valid response. // Site a.test is attested for Topics, so it should receive a valid response.
IN_PROC_BROWSER_TEST_F(AttestationBrowsingTopicsBrowserTest, IN_PROC_BROWSER_TEST_F(AttestationBrowsingTopicsBrowserTest,
AttestedSiteCanGetBrowsingTopicsViaDocumentAPI) { AttestedSiteCanGetBrowsingTopicsViaDocumentAPI) {
@@ -2683,8 +2542,8 @@ IN_PROC_BROWSER_TEST_F(
EXPECT_FALSE(console_observer.messages().empty()); EXPECT_FALSE(console_observer.messages().empty());
} }
IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest, IN_PROC_BROWSER_TEST_F(AttestationBrowsingTopicsBrowserTest,
SameOrigin_TopicsEligible_SendTopics_SiteAttested) { FetchSameOrigin_TopicsEligible_SendTopics_SiteAttested) {
privacy_sandbox::PrivacySandboxAttestationsMap map; privacy_sandbox::PrivacySandboxAttestationsMap map;
map.insert_or_assign( map.insert_or_assign(
net::SchemefulSite(GURL("https://a.test")), net::SchemefulSite(GURL("https://a.test")),
@@ -2700,12 +2559,16 @@ IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest,
https_server_.GetURL("a.test", "/browsing_topics/empty_page.html"); https_server_.GetURL("a.test", "/browsing_topics/empty_page.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url)); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
GURL resource_url = https_server_.GetURL("a.test", GetRelativePath()); GURL fetch_url = https_server_.GetURL(
"a.test", "/browsing_topics/page_with_custom_topics_header.html");
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
EXPECT_TRUE(topics_header_value); EXPECT_TRUE(topics_header_value);
EXPECT_EQ(*topics_header_value, kExpectedHeaderValueForSiteA); EXPECT_EQ(*topics_header_value, kExpectedHeaderValueForSiteA);
@@ -2713,8 +2576,8 @@ IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest,
EXPECT_TRUE(console_observer.messages().empty()); EXPECT_TRUE(console_observer.messages().empty());
} }
IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest, IN_PROC_BROWSER_TEST_F(AttestationBrowsingTopicsBrowserTest,
SameOrigin_TopicsEligible_SiteNotAttested) { FetchSameOrigin_TopicsEligible_SiteNotAttested) {
privacy_sandbox::PrivacySandboxAttestationsMap map; privacy_sandbox::PrivacySandboxAttestationsMap map;
map.insert_or_assign( map.insert_or_assign(
net::SchemefulSite(GURL("https://b.test")), net::SchemefulSite(GURL("https://b.test")),
@@ -2730,12 +2593,16 @@ IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest,
https_server_.GetURL("a.test", "/browsing_topics/empty_page.html"); https_server_.GetURL("a.test", "/browsing_topics/empty_page.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url)); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
GURL resource_url = https_server_.GetURL("a.test", GetRelativePath()); GURL fetch_url = https_server_.GetURL(
"a.test", "/browsing_topics/page_with_custom_topics_header.html");
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
EXPECT_EQ(topics_header_value, kExpectedHeaderValueForEmptyTopics); EXPECT_EQ(topics_header_value, kExpectedHeaderValueForEmptyTopics);
@@ -2743,8 +2610,9 @@ IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest,
EXPECT_FALSE(console_observer.messages().empty()); EXPECT_FALSE(console_observer.messages().empty());
} }
IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest, IN_PROC_BROWSER_TEST_F(
SameOrigin_TopicsEligible_SiteAttested_MismatchedMap) { AttestationBrowsingTopicsBrowserTest,
FetchSameOrigin_TopicsEligible_SiteAttested_MismatchedMap) {
privacy_sandbox::PrivacySandboxAttestationsMap map; privacy_sandbox::PrivacySandboxAttestationsMap map;
map.insert_or_assign(net::SchemefulSite(GURL("https://a.test")), map.insert_or_assign(net::SchemefulSite(GURL("https://a.test")),
privacy_sandbox::PrivacySandboxAttestationsGatedAPISet{ privacy_sandbox::PrivacySandboxAttestationsGatedAPISet{
@@ -2760,12 +2628,16 @@ IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest,
https_server_.GetURL("a.test", "/browsing_topics/empty_page.html"); https_server_.GetURL("a.test", "/browsing_topics/empty_page.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url)); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
GURL resource_url = https_server_.GetURL("a.test", GetRelativePath()); GURL fetch_url = https_server_.GetURL(
"a.test", "/browsing_topics/page_with_custom_topics_header.html");
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
EXPECT_EQ(topics_header_value, kExpectedHeaderValueForEmptyTopics); EXPECT_EQ(topics_header_value, kExpectedHeaderValueForEmptyTopics);
@@ -2775,9 +2647,9 @@ IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest,
// Site a.test is attested, so when an x-origin request is made to it from // Site a.test is attested, so when an x-origin request is made to it from
// site b.test, a.test should still include a topics header. // site b.test, a.test should still include a topics header.
IN_PROC_BROWSER_TEST_P( IN_PROC_BROWSER_TEST_F(
AttestationSubresourceRequestTest, AttestationBrowsingTopicsBrowserTest,
CrossOrigin_TopicsEligible_SendTopics_HasObserveResponse_SiteAttested) { FetchCrossOrigin_TopicsEligible_SendTopics_HasObserveResponse_SiteAttested) {
privacy_sandbox::PrivacySandboxAttestationsMap map; privacy_sandbox::PrivacySandboxAttestationsMap map;
map.insert_or_assign( map.insert_or_assign(
net::SchemefulSite(GURL("https://a.test")), net::SchemefulSite(GURL("https://a.test")),
@@ -2799,14 +2671,19 @@ IN_PROC_BROWSER_TEST_P(
"Observe-Browsing-Topics: ?1")); "Observe-Browsing-Topics: ?1"));
replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", "")); replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", ""));
GURL resource_url = https_server_.GetURL( GURL fetch_url = https_server_.GetURL(
"a.test", net::test_server::GetFilePathWithReplacements(GetRelativePath(), "a.test", net::test_server::GetFilePathWithReplacements(
replacement)); "/browsing_topics/"
"page_with_custom_topics_header.html",
replacement));
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
EXPECT_TRUE(topics_header_value); EXPECT_TRUE(topics_header_value);
EXPECT_EQ(*topics_header_value, kExpectedHeaderValueForSiteB); EXPECT_EQ(*topics_header_value, kExpectedHeaderValueForSiteB);
@@ -2831,8 +2708,8 @@ IN_PROC_BROWSER_TEST_P(
// Site a.test is not attested, so this should not generate a Topics header in a // Site a.test is not attested, so this should not generate a Topics header in a
// x-origin fetch to site a.test. // x-origin fetch to site a.test.
IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest, IN_PROC_BROWSER_TEST_F(AttestationBrowsingTopicsBrowserTest,
CrossOrigin_TopicsEligible_SiteNotAttested) { FetchCrossOrigin_TopicsEligible_SiteNotAttested) {
privacy_sandbox::PrivacySandboxAttestationsMap map; privacy_sandbox::PrivacySandboxAttestationsMap map;
map.insert_or_assign( map.insert_or_assign(
net::SchemefulSite(GURL("https://b.test")), net::SchemefulSite(GURL("https://b.test")),
@@ -2854,14 +2731,19 @@ IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest,
"Observe-Browsing-Topics: ?1")); "Observe-Browsing-Topics: ?1"));
replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", "")); replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", ""));
GURL resource_url = https_server_.GetURL( GURL fetch_url = https_server_.GetURL(
"a.test", net::test_server::GetFilePathWithReplacements(GetRelativePath(), "a.test", net::test_server::GetFilePathWithReplacements(
replacement)); "/browsing_topics/"
"page_with_custom_topics_header.html",
replacement));
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
EXPECT_EQ(topics_header_value, kExpectedHeaderValueForEmptyTopics); EXPECT_EQ(topics_header_value, kExpectedHeaderValueForEmptyTopics);
@@ -2875,11 +2757,11 @@ IN_PROC_BROWSER_TEST_P(AttestationSubresourceRequestTest,
EXPECT_FALSE(console_observer.messages().empty()); EXPECT_FALSE(console_observer.messages().empty());
} }
// Site a.test is attested, but not for Topics, so the fetch/img request to // Site a.test is attested, but not for Topics, so the fetch request to a.test
// a.test should not get a header. // should not get a header.
IN_PROC_BROWSER_TEST_P( IN_PROC_BROWSER_TEST_F(
AttestationSubresourceRequestTest, AttestationBrowsingTopicsBrowserTest,
CrossOrigin_TopicsEligible_SiteNotAttested_MismatchedMap) { FetchCrossOrigin_TopicsEligible_SiteNotAttested_MismatchedMap) {
privacy_sandbox::PrivacySandboxAttestationsMap map; privacy_sandbox::PrivacySandboxAttestationsMap map;
map.insert_or_assign(net::SchemefulSite(GURL("https://a.test")), map.insert_or_assign(net::SchemefulSite(GURL("https://a.test")),
privacy_sandbox::PrivacySandboxAttestationsGatedAPISet{ privacy_sandbox::PrivacySandboxAttestationsGatedAPISet{
@@ -2901,14 +2783,19 @@ IN_PROC_BROWSER_TEST_P(
"Observe-Browsing-Topics: ?1")); "Observe-Browsing-Topics: ?1"));
replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", "")); replacement.emplace_back(std::make_pair("{{REDIRECT_HEADER}}", ""));
GURL resource_url = https_server_.GetURL( GURL fetch_url = https_server_.GetURL(
"a.test", net::test_server::GetFilePathWithReplacements(GetRelativePath(), "a.test", net::test_server::GetFilePathWithReplacements(
replacement)); "/browsing_topics/"
"page_with_custom_topics_header.html",
replacement));
EXPECT_TRUE(ExecJsWithBrowsingTopicsTrue(resource_url)); EXPECT_TRUE(ExecJs(
web_contents()->GetPrimaryMainFrame(),
content::JsReplace("fetch($1, {browsingTopics: true})", fetch_url)));
std::optional<std::string> topics_header_value = std::optional<std::string> topics_header_value =
GetTopicsHeaderForRequestPath(GetRelativePath()); GetTopicsHeaderForRequestPath(
"/browsing_topics/page_with_custom_topics_header.html");
EXPECT_EQ(topics_header_value, kExpectedHeaderValueForEmptyTopics); EXPECT_EQ(topics_header_value, kExpectedHeaderValueForEmptyTopics);

Binary file not shown.

Before

(image error) Size: 119 B

@@ -1,4 +0,0 @@
HTTP/1.1 {{STATUS}}
Access-Control-Allow-Origin: *
{{OBSERVE_BROWSING_TOPICS_HEADER}}
{{REDIRECT_HEADER}}

Binary file not shown.

Before

(image error) Size: 119 B

@@ -1,4 +0,0 @@
HTTP/1.1 {{STATUS}}
Access-Control-Allow-Origin: *
{{OBSERVE_BROWSING_TOPICS_HEADER}}
{{REDIRECT_HEADER}}

@@ -270,14 +270,7 @@ enum class BrowsingTopicsApiActionType {
// <iframe src=[url] browsingtopics> request. // <iframe src=[url] browsingtopics> request.
kObserveViaIframeAttributeApi = 5, kObserveViaIframeAttributeApi = 5,
// Get topics via <img src=[url] browsingtopics>. kMaxValue = kObserveViaIframeAttributeApi,
kGetViaImgAttributeApi = 6,
// Observe topics via the "Sec-Browsing-Topics: ?1" response header for the
// <img src=[url] browsingtopics> request.
kObserveViaImgAttributeApi = 7,
kMaxValue = kObserveViaImgAttributeApi,
}; };
void RecordBrowsingTopicsApiActionTypeMetrics(ApiCallerSource caller_source, void RecordBrowsingTopicsApiActionTypeMetrics(ApiCallerSource caller_source,
@@ -321,24 +314,6 @@ void RecordBrowsingTopicsApiActionTypeMetrics(ApiCallerSource caller_source,
return; return;
} }
if (caller_source == ApiCallerSource::kImgAttribute) {
if (get_topics) {
DCHECK(!observe);
base::UmaHistogramEnumeration(
kBrowsingTopicsApiActionTypeHistogramId,
BrowsingTopicsApiActionType::kGetViaImgAttributeApi);
return;
}
DCHECK(observe);
base::UmaHistogramEnumeration(
kBrowsingTopicsApiActionTypeHistogramId,
BrowsingTopicsApiActionType::kObserveViaImgAttributeApi);
return;
}
DCHECK_EQ(caller_source, ApiCallerSource::kFetch); DCHECK_EQ(caller_source, ApiCallerSource::kFetch);
if (get_topics) { if (get_topics) {

@@ -40,9 +40,6 @@ enum class ApiCallerSource {
// The API usage is from <iframe src=[url] browsingtopics>. // The API usage is from <iframe src=[url] browsingtopics>.
kIframeAttribute, kIframeAttribute,
// The API usage is from <img src=[url] browsingtopics>.
kImgAttribute,
}; };
// Represents the different reasons why the topics API access is denied. These // Represents the different reasons why the topics API access is denied. These

@@ -4,7 +4,6 @@
#include "content/browser/browsing_topics/browsing_topics_url_loader_interceptor.h" #include "content/browser/browsing_topics/browsing_topics_url_loader_interceptor.h"
#include "components/browsing_topics/common/common_types.h"
#include "content/browser/browsing_topics/header_util.h" #include "content/browser/browsing_topics/header_util.h"
#include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/public/browser/content_browser_client.h" #include "content/public/browser/content_browser_client.h"
@@ -171,9 +170,7 @@ void BrowsingTopicsURLLoaderInterceptor::PopulateRequestOrRedirectHeaders(
std::vector<blink::mojom::EpochTopicPtr> topics; std::vector<blink::mojom::EpochTopicPtr> topics;
topics_eligible_ = GetContentClient()->browser()->HandleTopicsWebApi( topics_eligible_ = GetContentClient()->browser()->HandleTopicsWebApi(
origin, request_initiator_frame->GetMainFrame(), origin, request_initiator_frame->GetMainFrame(),
resource_request_->is_fetch_like_api browsing_topics::ApiCallerSource::kFetch,
? browsing_topics::ApiCallerSource::kFetch
: browsing_topics::ApiCallerSource::kImgAttribute,
/*get_topics=*/true, /*get_topics=*/true,
/*observe=*/false, topics); /*observe=*/false, topics);
@@ -203,11 +200,9 @@ void BrowsingTopicsURLLoaderInterceptor::ProcessRedirectOrResponseHeaders(
return; return;
} }
HandleTopicsEligibleResponse( HandleTopicsEligibleResponse(head->parsed_headers,
head->parsed_headers, url::Origin::Create(url_), *rfh, url::Origin::Create(url_), *rfh,
resource_request_->is_fetch_like_api browsing_topics::ApiCallerSource::kFetch);
? browsing_topics::ApiCallerSource::kFetch
: browsing_topics::ApiCallerSource::kImgAttribute);
topics_eligible_ = false; topics_eligible_ = false;
} }

@@ -5,7 +5,6 @@
#include "content/browser/browsing_topics/header_util.h" #include "content/browser/browsing_topics/header_util.h"
#include "base/strings/strcat.h" #include "base/strings/strcat.h"
#include "components/browsing_topics/common/common_types.h"
#include "components/browsing_topics/common/semantic_tree.h" #include "components/browsing_topics/common/semantic_tree.h"
#include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/public/browser/content_browser_client.h" #include "content/public/browser/content_browser_client.h"
@@ -149,8 +148,7 @@ void HandleTopicsEligibleResponse(
RenderFrameHost& request_initiator_frame, RenderFrameHost& request_initiator_frame,
browsing_topics::ApiCallerSource caller_source) { browsing_topics::ApiCallerSource caller_source) {
DCHECK(caller_source == browsing_topics::ApiCallerSource::kFetch || DCHECK(caller_source == browsing_topics::ApiCallerSource::kFetch ||
caller_source == browsing_topics::ApiCallerSource::kIframeAttribute || caller_source == browsing_topics::ApiCallerSource::kIframeAttribute);
caller_source == browsing_topics::ApiCallerSource::kImgAttribute);
if (!parsed_headers || !parsed_headers->observe_browsing_topics) { if (!parsed_headers || !parsed_headers->observe_browsing_topics) {
return; return;

@@ -395,9 +395,6 @@ void SetRuntimeFeaturesFromChromiumFeatures() {
kSetOnlyIfOverridden}, kSetOnlyIfOverridden},
{"TopicsDocumentAPI", {"TopicsDocumentAPI",
raw_ref(features::kPrivacySandboxAdsAPIsM1Override)}, raw_ref(features::kPrivacySandboxAdsAPIsM1Override)},
{"TopicsImgAPI", raw_ref(features::kPrivacySandboxAdsAPIsOverride),
kSetOnlyIfOverridden},
{"TopicsImgAPI", raw_ref(features::kPrivacySandboxAdsAPIsM1Override)},
{"TouchTextEditingRedesign", {"TouchTextEditingRedesign",
raw_ref(features::kTouchTextEditingRedesign)}, raw_ref(features::kTouchTextEditingRedesign)},
{"TrustedTypesFromLiteral", {"TrustedTypesFromLiteral",
@@ -586,7 +583,6 @@ void ResolveInvalidConfigurations() {
<< blink::features::kBrowsingTopics.name << " in addition."; << blink::features::kBrowsingTopics.name << " in addition.";
WebRuntimeFeatures::EnableTopicsAPI(false); WebRuntimeFeatures::EnableTopicsAPI(false);
WebRuntimeFeatures::EnableTopicsDocumentAPI(false); WebRuntimeFeatures::EnableTopicsDocumentAPI(false);
WebRuntimeFeatures::EnableTopicsImgAPI(false);
} else { } else {
if (!base::FeatureList::IsEnabled( if (!base::FeatureList::IsEnabled(
blink::features::kBrowsingTopicsDocumentAPI)) { blink::features::kBrowsingTopicsDocumentAPI)) {

@@ -4619,7 +4619,6 @@ enum WebFeature {
kInjectionMitigatedContextSubFrame = 5233, kInjectionMitigatedContextSubFrame = 5233,
kInjectionMitigatedContextMainFrame = 5234, kInjectionMitigatedContextMainFrame = 5234,
kCanvasTextDirectionConflict = 5235, kCanvasTextDirectionConflict = 5235,
kTopicsAPIImg = 5236,
// Add new features immediately above this line. Don't change assigned // Add new features immediately above this line. Don't change assigned
// numbers of any item, and don't reuse removed slots. Also don't add extra // numbers of any item, and don't reuse removed slots. Also don't add extra

@@ -63,9 +63,6 @@
[MeasureAs=HTMLImageElementY] readonly attribute long y; [MeasureAs=HTMLImageElementY] readonly attribute long y;
[CallWith=ScriptState, RaisesException] Promise<undefined> decode(); [CallWith=ScriptState, RaisesException] Promise<undefined> decode();
// Topics API (https://github.com/patcg-individual-drafts/topics)
[RuntimeEnabled=TopicsImgAPI, SecureContext, CEReactions, Reflect] attribute boolean browsingTopics;
}; };
HTMLImageElement includes HTMLAttributionSrcElementUtils; HTMLImageElement includes HTMLAttributionSrcElementUtils;

@@ -369,11 +369,6 @@ class TokenPreloadScanner::StartTagScanner {
request->SetSharedStorageWritableOptedIn(true); request->SetSharedStorageWritableOptedIn(true);
} }
if (browsing_topics_attr_set_) {
DCHECK(is_img);
request->SetBrowsingTopicsEligible(true);
}
return request; return request;
} }
@@ -456,8 +451,6 @@ class TokenPreloadScanner::StartTagScanner {
attributionsrc_attr_set_ = true; attributionsrc_attr_set_ = true;
} else if (Match(attribute_name, html_names::kSharedstoragewritableAttr)) { } else if (Match(attribute_name, html_names::kSharedstoragewritableAttr)) {
shared_storage_writable_opted_in_ = true; shared_storage_writable_opted_in_ = true;
} else if (Match(attribute_name, html_names::kBrowsingtopicsAttr)) {
browsing_topics_attr_set_ = true;
} else if (use_data_src_attr_match_for_image_ && } else if (use_data_src_attr_match_for_image_ &&
Match(attribute_name, html_names::kDataSrcAttr) && Match(attribute_name, html_names::kDataSrcAttr) &&
img_src_url_.IsNull()) { img_src_url_.IsNull()) {
@@ -825,7 +818,6 @@ class TokenPreloadScanner::StartTagScanner {
const HashSet<String>* disabled_image_types_; const HashSet<String>* disabled_image_types_;
bool attributionsrc_attr_set_ = false; bool attributionsrc_attr_set_ = false;
bool shared_storage_writable_opted_in_ = false; bool shared_storage_writable_opted_in_ = false;
bool browsing_topics_attr_set_ = false;
std::optional<float> resource_width_; std::optional<float> resource_width_;
std::optional<float> resource_height_; std::optional<float> resource_height_;
features::LcppPreloadLazyLoadImageType preload_lazy_load_image_type_; features::LcppPreloadLazyLoadImageType preload_lazy_load_image_type_;

@@ -130,13 +130,6 @@ struct SharedStorageWritableTestCase {
bool expected_shared_storage_writable_opted_in; bool expected_shared_storage_writable_opted_in;
}; };
struct BrowsingTopicsWritableTestCase {
bool use_secure_document_url;
const char* base_url;
const char* input_html;
bool expected_browsing_topics;
};
class HTMLMockHTMLResourcePreloader : public ResourcePreloader { class HTMLMockHTMLResourcePreloader : public ResourcePreloader {
public: public:
explicit HTMLMockHTMLResourcePreloader(const KURL& document_url) explicit HTMLMockHTMLResourcePreloader(const KURL& document_url)
@@ -316,16 +309,6 @@ class HTMLMockHTMLResourcePreloader : public ResourcePreloader {
resource->GetResourceRequest().GetSharedStorageWritableOptedIn()); resource->GetResourceRequest().GetSharedStorageWritableOptedIn());
} }
void BrowsingTopicsRequestVerification(Document* document,
bool expected_browsing_topics) {
ASSERT_TRUE(preload_request_.get());
Resource* resource = preload_request_->Start(document);
ASSERT_TRUE(resource);
EXPECT_EQ(expected_browsing_topics,
resource->GetResourceRequest().GetBrowsingTopics());
}
protected: protected:
void Preload(std::unique_ptr<PreloadRequest> preload_request) override { void Preload(std::unique_ptr<PreloadRequest> preload_request) override {
preload_request_ = std::move(preload_request); preload_request_ = std::move(preload_request);
@@ -563,20 +546,6 @@ class HTMLPreloadScannerTest : public PageTestBase {
&GetDocument(), test_case.expected_shared_storage_writable_opted_in); &GetDocument(), test_case.expected_shared_storage_writable_opted_in);
} }
void Test(BrowsingTopicsWritableTestCase test_case) {
SCOPED_TRACE(base::StringPrintf("Use secure doc URL: %d; HTML: '%s'",
test_case.use_secure_document_url,
test_case.input_html));
HTMLMockHTMLResourcePreloader preloader(GetDocument().Url());
KURL base_url(test_case.base_url);
scanner_->AppendToEnd(String(test_case.input_html));
std::unique_ptr<PendingPreloadData> preload_data = scanner_->Scan(base_url);
preloader.TakePreloadData(std::move(preload_data));
preloader.BrowsingTopicsRequestVerification(
&GetDocument(), test_case.expected_browsing_topics);
}
private: private:
std::unique_ptr<HTMLPreloadScanner> scanner_; std::unique_ptr<HTMLPreloadScanner> scanner_;
}; };
@@ -2021,42 +1990,4 @@ TEST_F(HTMLPreloadScannerTest, PreloadScanDisabled_NoPreloads) {
} }
} }
TEST_F(HTMLPreloadScannerTest, testBrowsingTopics) {
WebRuntimeFeaturesBase::EnableTopicsAPI(true);
static constexpr bool kSecureDocumentUrl = true;
static constexpr bool kInsecureDocumentUrl = false;
static constexpr char kSecureBaseURL[] = "https://example.test";
static constexpr char kInsecureBaseURL[] = "http://example.test";
BrowsingTopicsWritableTestCase test_cases[] = {
// Insecure context
{kInsecureDocumentUrl, kSecureBaseURL,
"<img src='/image' browsingtopics>",
/*expected_browsing_topics=*/false},
// No browsingtopics attribute
{kSecureDocumentUrl, kSecureBaseURL, "<img src='/image'>",
/*expected_browsing_topics=*/false},
// Irrelevant element type
{kSecureDocumentUrl, kSecureBaseURL,
"<video poster='/image' browsingtopics>",
/*expected_browsing_topics=*/false},
// Secure context, browsingtopics attribute
// Base (initial) URL does not affect SharedStorageWritable eligibility
{kSecureDocumentUrl, kInsecureBaseURL,
"<img src='/image' browsingtopics>",
/*expected_browsing_topics=*/true},
// Secure context, browsingtopics attribute
{kSecureDocumentUrl, kSecureBaseURL, "<img src='/image' browsingtopics>",
/*expected_browsing_topics=*/true},
};
for (const auto& test_case : test_cases) {
RunSetUp(kViewportDisabled, kPreloadEnabled,
network::mojom::ReferrerPolicy::kDefault,
/*use_secure_document_url=*/test_case.use_secure_document_url);
Test(test_case);
}
}
} // namespace blink } // namespace blink

@@ -140,12 +140,6 @@ Resource* PreloadRequest::Start(Document* document) {
UseCounter::Count(document, WebFeature::kSharedStorageAPI_Image_Attribute); UseCounter::Count(document, WebFeature::kSharedStorageAPI_Image_Attribute);
} }
bool browsing_topics =
browsing_topics_eligible_ && RuntimeEnabledFeatures::TopicsAPIEnabled() &&
document->domWindow()->IsSecureContext() &&
!document->domWindow()->GetSecurityOrigin()->IsOpaque();
resource_request.SetBrowsingTopics(browsing_topics);
ResourceLoaderOptions options(document->domWindow()->GetCurrentWorld()); ResourceLoaderOptions options(document->domWindow()->GetCurrentWorld());
options.initiator_info = initiator_info; options.initiator_info = initiator_info;
FetchParameters params(std::move(resource_request), options); FetchParameters params(std::move(resource_request), options);

@@ -159,14 +159,6 @@ class CORE_EXPORT PreloadRequest {
shared_storage_writable_opted_in_ = opted_in; shared_storage_writable_opted_in_ = opted_in;
} }
// Set whether the preload request is eligible for the Browsing Topics API.
//
// See https://github.com/patcg-individual-drafts/topics/blob/main/README.md
// for the latest version of the Topics API explainer.
void SetBrowsingTopicsEligible(bool flag) {
browsing_topics_eligible_ = flag;
}
bool IsPotentiallyLCPElement() const { return is_potentially_lcp_element_; } bool IsPotentiallyLCPElement() const { return is_potentially_lcp_element_; }
bool IsPotentiallyLCPInfluencer() const { bool IsPotentiallyLCPInfluencer() const {
@@ -225,7 +217,6 @@ class CORE_EXPORT PreloadRequest {
bool is_potentially_lcp_element_ = false; bool is_potentially_lcp_element_ = false;
bool is_potentially_lcp_influencer_ = false; bool is_potentially_lcp_influencer_ = false;
bool shared_storage_writable_opted_in_ = false; bool shared_storage_writable_opted_in_ = false;
bool browsing_topics_eligible_ = false;
}; };
typedef Vector<std::unique_ptr<PreloadRequest>> PreloadRequestStream; typedef Vector<std::unique_ptr<PreloadRequest>> PreloadRequestStream;

@@ -507,14 +507,6 @@ void ImageLoader::DoUpdateFromElement(const DOMWrapperWorld* world,
!SecurityOrigin::Create(url)->IsOpaque(); !SecurityOrigin::Create(url)->IsOpaque();
resource_request.SetSharedStorageWritableOptedIn( resource_request.SetSharedStorageWritableOptedIn(
shared_storage_writable_opted_in); shared_storage_writable_opted_in);
if (GetElement()->FastHasAttribute(html_names::kBrowsingtopicsAttr) &&
RuntimeEnabledFeatures::TopicsAPIEnabled(
GetElement()->GetExecutionContext()) &&
GetElement()->GetExecutionContext()->IsSecureContext()) {
resource_request.SetBrowsingTopics(true);
UseCounter::Count(document, mojom::blink::WebFeature::kTopicsAPIImg);
UseCounter::Count(document, mojom::blink::WebFeature::kTopicsAPIAll);
}
} }
bool page_is_being_dismissed = bool page_is_being_dismissed =

@@ -4297,14 +4297,6 @@
public: true, public: true,
status: "stable", status: "stable",
}, },
{
// This feature allows calling the Topics API via an image
// attribute.
name: "TopicsImgAPI",
base_feature: "none",
public: true,
status: "experimental",
},
// This is a killswitch for the behavior where popover.showPopover() and // This is a killswitch for the behavior where popover.showPopover() and
// dialog.showModal() throw DOM exceptions if the document isn't active. // dialog.showModal() throw DOM exceptions if the document isn't active.
// This landed in M132, and can be removed in M134. // This landed in M132, and can be removed in M134.

@@ -692,7 +692,6 @@ html element img
property alt property alt
property attributionSrc property attributionSrc
property border property border
property browsingTopics
property complete property complete
property crossOrigin property crossOrigin
property currentSrc property currentSrc

@@ -3895,7 +3895,6 @@ interface HTMLImageElement : HTMLElement
getter alt getter alt
getter attributionSrc getter attributionSrc
getter border getter border
getter browsingTopics
getter complete getter complete
getter crossOrigin getter crossOrigin
getter currentSrc getter currentSrc
@@ -3926,7 +3925,6 @@ interface HTMLImageElement : HTMLElement
setter alt setter alt
setter attributionSrc setter attributionSrc
setter border setter border
setter browsingTopics
setter crossOrigin setter crossOrigin
setter decoding setter decoding
setter fetchPriority setter fetchPriority
@@ -5006,7 +5004,6 @@ interface Image
getter alt getter alt
getter attributionSrc getter attributionSrc
getter border getter border
getter browsingTopics
getter complete getter complete
getter crossOrigin getter crossOrigin
getter currentSrc getter currentSrc
@@ -5037,7 +5034,6 @@ interface Image
setter alt setter alt
setter attributionSrc setter attributionSrc
setter border setter border
setter browsingTopics
setter crossOrigin setter crossOrigin
setter decoding setter decoding
setter fetchPriority setter fetchPriority

@@ -728,7 +728,6 @@ html element img
property alt property alt
property attributionSrc property attributionSrc
property border property border
property browsingTopics
property complete property complete
property crossOrigin property crossOrigin
property currentSrc property currentSrc

@@ -4329,7 +4329,6 @@ interface HTMLImageElement : HTMLElement
getter alt getter alt
getter attributionSrc getter attributionSrc
getter border getter border
getter browsingTopics
getter complete getter complete
getter crossOrigin getter crossOrigin
getter currentSrc getter currentSrc
@@ -4360,7 +4359,6 @@ interface HTMLImageElement : HTMLElement
setter alt setter alt
setter attributionSrc setter attributionSrc
setter border setter border
setter browsingTopics
setter crossOrigin setter crossOrigin
setter decoding setter decoding
setter fetchPriority setter fetchPriority
@@ -5486,7 +5484,6 @@ interface Image
getter alt getter alt
getter attributionSrc getter attributionSrc
getter border getter border
getter browsingTopics
getter complete getter complete
getter crossOrigin getter crossOrigin
getter currentSrc getter currentSrc
@@ -5517,7 +5514,6 @@ interface Image
setter alt setter alt
setter attributionSrc setter attributionSrc
setter border setter border
setter browsingTopics
setter crossOrigin setter crossOrigin
setter decoding setter decoding
setter fetchPriority setter fetchPriority

@@ -10952,7 +10952,6 @@ Called by update_use_counter_feature_enum.py.-->
<int value="5233" label="InjectionMitigatedContextSubFrame"/> <int value="5233" label="InjectionMitigatedContextSubFrame"/>
<int value="5234" label="InjectionMitigatedContextMainFrame"/> <int value="5234" label="InjectionMitigatedContextMainFrame"/>
<int value="5235" label="CanvasTextDirectionConflict"/> <int value="5235" label="CanvasTextDirectionConflict"/>
<int value="5236" label="TopicsAPIImg"/>
</enum> </enum>
<!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom:WebFeature) --> <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom:WebFeature) -->

@@ -33,8 +33,6 @@ chromium-metrics-reviews@google.com.
<int value="3" label="observe via fetch-like api"/> <int value="3" label="observe via fetch-like api"/>
<int value="4" label="get via iframe attribute api"/> <int value="4" label="get via iframe attribute api"/>
<int value="5" label="observe via iframe attribute api"/> <int value="5" label="observe via iframe attribute api"/>
<int value="6" label="get via img attribute api"/>
<int value="7" label="observe via img attribute api"/>
</enum> </enum>
<enum name="BrowsingTopicsCalculatorResultStatus"> <enum name="BrowsingTopicsCalculatorResultStatus">