blink: splice fragment identifier into canonical URL for sharing
If:
* The document has a non-empty canonical URL,
* The document's canonical URL has no fragment identifier,
* The document's URL has a fragment identifier,
then include the document URL's fragment identifier in the canonical
URL for sharing purposes. This allows sharing URLs that reference
a specific anchor within the page. For example, when visiting a mobile
Wikipedia page, this allows the user to share a reference to a specific
section even though the page's canonical URL references the page as a
whole.
Note that this change applies only to fragment identifiers, not to
fragment directives (like text highlight directives) - those are
consumed in Document::SetURL and not part of the document's URL.
Fixed: 1038187
Change-Id: Ie7f562ebf74735ccc271e41c488012a952118d9b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3237449
Commit-Queue: Elly Fong-Jones <ellyjones@chromium.org>
Reviewed-by: sebsg <sebsg@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/main@{#934606}
diff --git a/third_party/blink/renderer/core/exported/web_document.cc b/third_party/blink/renderer/core/exported/web_document.cc
index 79c2557..f3e93676 100644
--- a/third_party/blink/renderer/core/exported/web_document.cc
+++ b/third_party/blink/renderer/core/exported/web_document.cc
@@ -278,7 +278,11 @@
HTMLLinkElement* link_element = document->LinkCanonical();
if (!link_element)
return WebURL();
- return link_element->Href();
+ KURL canon_url = link_element->Href();
+ KURL doc_url = document->Url();
+ if (doc_url.HasFragmentIdentifier() && !canon_url.HasFragmentIdentifier())
+ canon_url.SetFragmentIdentifier(doc_url.FragmentIdentifier());
+ return canon_url;
}
WebDistillabilityFeatures WebDocument::DistillabilityFeatures() {
diff --git a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
index 16d874f4..dbf61a85 100644
--- a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
@@ -1082,13 +1082,20 @@
void LocalFrameMojoHandler::GetCanonicalUrlForSharing(
GetCanonicalUrlForSharingCallback callback) {
- KURL canonical_url;
+ KURL canon_url;
HTMLLinkElement* link_element = GetDocument()->LinkCanonical();
- if (link_element)
- canonical_url = link_element->Href();
- std::move(callback).Run(canonical_url.IsNull()
- ? absl::nullopt
- : absl::make_optional(canonical_url));
+ if (link_element) {
+ canon_url = link_element->Href();
+ KURL doc_url = GetDocument()->Url();
+ // When sharing links to pages, the fragment identifier often serves to mark a specific place
+ // within the page that the user wishes to point the recipient to. Canonical URLs generally
+ // don't and can't contain this state, so try to match user expectations a little more closely
+ // here by splicing the fragment identifier (if there is one) into the shared URL.
+ if (doc_url.HasFragmentIdentifier() && !canon_url.HasFragmentIdentifier())
+ canon_url.SetFragmentIdentifier(doc_url.FragmentIdentifier());
+ }
+ std::move(callback).Run(canon_url.IsNull() ? absl::nullopt
+ : absl::make_optional(canon_url));
}
void LocalFrameMojoHandler::AnimateDoubleTapZoom(const gfx::Point& point,
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index 977c14f..e1b0fd7 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -13369,6 +13369,34 @@
frame->GetDocument().CanonicalUrlForSharing());
}
+TEST_F(WebFrameTest, GetCanonicalURLWithCanonicalFragment) {
+ frame_test_helpers::WebViewHelper web_view_helper;
+ web_view_helper.Initialize();
+ WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
+ frame_test_helpers::LoadHTMLString(
+ frame, R"(
+ <head>
+ <link rel="canonical" href="https://example.com/canonical.html#a1">
+ </head>)",
+ ToKURL("https://example.com/test_page.html#a2"));
+ EXPECT_EQ(WebURL(ToKURL("https://example.com/canonical.html#a1")),
+ frame->GetDocument().CanonicalUrlForSharing());
+}
+
+TEST_F(WebFrameTest, GetCanonicalURLWithDocumentFragment) {
+ frame_test_helpers::WebViewHelper web_view_helper;
+ web_view_helper.Initialize();
+ WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
+ frame_test_helpers::LoadHTMLString(
+ frame, R"(
+ <head>
+ <link rel="canonical" href="https://example.com/canonical.html">
+ </head>)",
+ ToKURL("https://example.com/test_page.html#a2"));
+ EXPECT_EQ(WebURL(ToKURL("https://example.com/canonical.html#a2")),
+ frame->GetDocument().CanonicalUrlForSharing());
+}
+
TEST_F(WebFrameSimTest, EnterFullscreenResetScrollAndScaleState) {
UseAndroidSettings();
WebView().MainFrameViewWidget()->Resize(gfx::Size(490, 500));