Avoid rewriting about:srcdoc into chrome://srcdoc
Rewriting about:srcdoc into chrome://srcdoc is undesirable because
1. about:srcdoc has a special meaning and just like about:blank has been
reserved by specs like
https://html.spec.whatwg.org/multipage/urls-and-fetching.html
2. chrome:-scheme URLs are special and might have extra privileges.
Therefore chrome: URLs should not be reachable by an unprivileged webpage
(OTOH, the rewriting fixed here only applies to the URL *shown* to
the user, not the URL that gets committed - compare WebContents's
GetVisibleURL vs GetLastCommittedURL).
Bug: 973628
Change-Id: I021e623caf0d7e5c02a2546291bb4913412b3125
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1654909
Auto-Submit: Łukasz Anforowicz <[email protected]>
Commit-Queue: Łukasz Anforowicz <[email protected]>
Commit-Queue: Avi Drissman <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Reviewed-by: Charlie Harrison <[email protected]>
Reviewed-by: Peter Kasting <[email protected]>
Cr-Commit-Position: refs/heads/master@{#669328}
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 55949cc..2b94c590 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -39,7 +39,8 @@
FixupBrowserAboutURL(url, browser_context);
// Check that about: URLs are fixed up to chrome: by url_formatter::FixupURL.
- DCHECK((url->IsAboutBlank()) || !url->SchemeIs(url::kAboutScheme));
+ DCHECK(url->IsAboutBlank() || url->IsAboutSrcdoc() ||
+ !url->SchemeIs(url::kAboutScheme));
// Only handle chrome://foo/, url_formatter::FixupURL translates about:foo.
if (!url->SchemeIs(content::kChromeUIScheme))
diff --git a/components/url_formatter/url_fixer.cc b/components/url_formatter/url_fixer.cc
index 3afc7008..502f598 100644
--- a/components/url_formatter/url_fixer.cc
+++ b/components/url_formatter/url_fixer.cc
@@ -563,11 +563,11 @@
return GURL();
}
- // 'about:blank' is special-cased in various places in the code so it
- // shouldn't be transformed into 'chrome://blank' as the code below will do.
+ // 'about:blank' and 'about:srcdoc' are special-cased in various places in the
+ // code and shouldn't use the chrome: scheme.
if (base::LowerCaseEqualsASCII(scheme, url::kAboutScheme)) {
GURL about_url(base::ToLowerASCII(trimmed));
- if (about_url.IsAboutBlank())
+ if (about_url.IsAboutBlank() || about_url.IsAboutSrcdoc())
return about_url;
}
diff --git a/components/url_formatter/url_fixer_unittest.cc b/components/url_formatter/url_fixer_unittest.cc
index 05a2b54..91c2115 100644
--- a/components/url_formatter/url_fixer_unittest.cc
+++ b/components/url_formatter/url_fixer_unittest.cc
@@ -311,9 +311,9 @@
if (url.length() <= 8)
return false;
if (std::string("file:///") != url.substr(0, 8))
- return false; // no file:/// prefix
+ return false; // no file:/// prefix
if (url.find('\\') != std::string::npos)
- return false; // contains backslashes
+ return false; // contains backslashes
base::FilePath derived_path;
net::FileURLToFilePath(GURL(url), &derived_path);
@@ -339,6 +339,11 @@
{"about:version", "chrome://version/"},
{"about:blank", "about:blank"},
{"About:blaNk", "about:blank"},
+ {"about:blank#blah", "about:blank#blah"},
+ {"about:blank/#blah", "about:blank/#blah"},
+ {"about:srcdoc", "about:srcdoc"},
+ {"about:srcdoc#blah", "about:srcdoc#blah"},
+ {"about:srcdoc/#blah", "about:srcdoc/#blah"},
{"about:usr:pwd@hst:20/pth?qry#ref", "chrome://hst/pth?qry#ref"},
{"about://usr:pwd@hst/pth?qry#ref", "chrome://hst/pth?qry#ref"},
{"chrome:usr:pwd@hst/pth?qry#ref", "chrome://hst/pth?qry#ref"},
@@ -398,7 +403,6 @@
{"chrome-devtools://bundled/devtools/inspector.html?ws=ws://localhost:9222/"
"guid",
"devtools://bundled/devtools/inspector.html?ws=ws://localhost:9222/guid"},
-
};
TEST(URLFixerTest, FixupURL) {
diff --git a/url/gurl.cc b/url/gurl.cc
index 84e7bf1..91b0f24 100644
--- a/url/gurl.cc
+++ b/url/gurl.cc
@@ -8,6 +8,7 @@
#include <algorithm>
#include <ostream>
+#include <utility>
#include "base/lazy_instance.h"
#include "base/logging.h"
@@ -339,16 +340,11 @@
}
bool GURL::IsAboutBlank() const {
- if (!SchemeIs(url::kAboutScheme))
- return false;
+ return IsAboutUrl(url::kAboutBlankPath);
+}
- if (has_host() || has_username() || has_password() || has_port())
- return false;
-
- if (path() != url::kAboutBlankPath && path() != url::kAboutBlankWithHashPath)
- return false;
-
- return true;
+bool GURL::IsAboutSrcdoc() const {
+ return IsAboutUrl(url::kAboutSrcdocPath);
}
bool GURL::SchemeIs(base::StringPiece lower_ascii_scheme) const {
@@ -487,6 +483,30 @@
(parsed_.inner_parsed() ? sizeof(url::Parsed) : 0);
}
+bool GURL::IsAboutUrl(base::StringPiece allowed_path) const {
+ if (!SchemeIs(url::kAboutScheme))
+ return false;
+
+ if (has_host() || has_username() || has_password() || has_port())
+ return false;
+
+ if (!path_piece().starts_with(allowed_path))
+ return false;
+
+ if (path_piece().size() == allowed_path.size()) {
+ DCHECK_EQ(path_piece(), allowed_path);
+ return true;
+ }
+
+ if ((path_piece().size() == allowed_path.size() + 1) &&
+ path_piece().back() == '/') {
+ DCHECK_EQ(path_piece(), allowed_path.as_string() + '/');
+ return true;
+ }
+
+ return false;
+}
+
std::ostream& operator<<(std::ostream& out, const GURL& url) {
return out << url.possibly_invalid_spec();
}
diff --git a/url/gurl.h b/url/gurl.h
index 1b0669e..9c680e0 100644
--- a/url/gurl.h
+++ b/url/gurl.h
@@ -217,6 +217,10 @@
// about:blank/#foo.
bool IsAboutBlank() const;
+ // Returns true when the url is of the form about:srcdoc, about:srcdoc?foo or
+ // about:srcdoc/#foo.
+ bool IsAboutSrcdoc() const;
+
// Returns true if the given parameter (should be lower-case ASCII to match
// the canonicalized scheme) is the scheme for this URL. Do not include a
// colon.
@@ -445,6 +449,9 @@
void InitializeFromCanonicalSpec();
+ // Helper used by IsAboutBlank and IsAboutSrcdoc.
+ bool IsAboutUrl(base::StringPiece allowed_path) const;
+
// Returns the substring of the input identified by the given component.
std::string ComponentString(const url::Component& comp) const {
if (comp.len <= 0)
diff --git a/url/gurl_unittest.cc b/url/gurl_unittest.cc
index 379c04f..0d7b65b 100644
--- a/url/gurl_unittest.cc
+++ b/url/gurl_unittest.cc
@@ -863,11 +863,34 @@
const std::string kNotAboutBlankUrls[] = {
"http:blank", "about:blan", "about://blank",
"about:blank/foo", "about://:8000/blank", "about://foo:foo@/blank",
- "foo@about:blank", "foo:bar@about:blank", "about:blank:8000"};
+ "foo@about:blank", "foo:bar@about:blank", "about:blank:8000",
+ "about:blANk"};
for (const auto& url : kNotAboutBlankUrls)
EXPECT_FALSE(GURL(url).IsAboutBlank()) << url;
}
+TEST(GURLTest, IsAboutSrcdoc) {
+ const std::string kAboutSrcdocUrls[] = {
+ "about:srcdoc", "about:srcdoc/", "about:srcdoc?foo", "about:srcdoc/#foo",
+ "about:srcdoc?foo#foo"};
+ for (const auto& url : kAboutSrcdocUrls)
+ EXPECT_TRUE(GURL(url).IsAboutSrcdoc()) << url;
+
+ const std::string kNotAboutSrcdocUrls[] = {"http:srcdoc",
+ "about:srcdo",
+ "about://srcdoc",
+ "about://srcdoc\\",
+ "about:srcdoc/foo",
+ "about://:8000/srcdoc",
+ "about://foo:foo@/srcdoc",
+ "foo@about:srcdoc",
+ "foo:bar@about:srcdoc",
+ "about:srcdoc:8000",
+ "about:srCDOc"};
+ for (const auto& url : kNotAboutSrcdocUrls)
+ EXPECT_FALSE(GURL(url).IsAboutSrcdoc()) << url;
+}
+
TEST(GURLTest, EqualsIgnoringRef) {
const struct {
const char* url_a;
diff --git a/url/url_constants.cc b/url/url_constants.cc
index 110c6a7b..38f86bbb 100644
--- a/url/url_constants.cc
+++ b/url/url_constants.cc
@@ -9,7 +9,7 @@
const char kAboutBlankURL[] = "about:blank";
const char kAboutBlankPath[] = "blank";
-const char kAboutBlankWithHashPath[] = "blank/";
+const char kAboutSrcdocPath[] = "srcdoc";
const char kAboutScheme[] = "about";
const char kBlobScheme[] = "blob";
diff --git a/url/url_constants.h b/url/url_constants.h
index 38a0e38..7f322f89 100644
--- a/url/url_constants.h
+++ b/url/url_constants.h
@@ -14,7 +14,7 @@
COMPONENT_EXPORT(URL) extern const char kAboutBlankURL[];
COMPONENT_EXPORT(URL) extern const char kAboutBlankPath[];
-COMPONENT_EXPORT(URL) extern const char kAboutBlankWithHashPath[];
+COMPONENT_EXPORT(URL) extern const char kAboutSrcdocPath[];
COMPONENT_EXPORT(URL) extern const char kAboutScheme[];
COMPONENT_EXPORT(URL) extern const char kBlobScheme[];