summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chromeos/fileapi/file_system_backend_unittest.cc2
-rw-r--r--chrome/common/chrome_content_client.cc30
-rw-r--r--chrome/common/chrome_content_client.h4
-rw-r--r--chrome/common/chrome_content_client_ios.mm3
-rw-r--r--chrome/common/chrome_content_client_unittest.cc18
-rw-r--r--components/test/run_all_unittests.cc8
-rw-r--r--content/browser/site_instance_impl_unittest.cc4
-rw-r--r--content/common/url_schemes.cc14
-rw-r--r--content/public/common/content_client.h3
-rw-r--r--extensions/shell/common/shell_content_client.cc14
-rw-r--r--extensions/shell/common/shell_content_client.h3
-rw-r--r--extensions/test/extensions_unittests_main.cc15
-rw-r--r--google_apis/drive/drive_api_url_generator_unittest.cc2
-rw-r--r--ios/chrome/test/ios_chrome_unit_test_suite.cc3
-rw-r--r--mojo/runner/url_resolver.cc2
-rw-r--r--url/scheme_host_port.cc153
-rw-r--r--url/scheme_host_port.h19
-rw-r--r--url/url_util.cc67
-rw-r--r--url/url_util.h33
-rw-r--r--url/url_util_unittest.cc34
20 files changed, 309 insertions, 122 deletions
diff --git a/chrome/browser/chromeos/fileapi/file_system_backend_unittest.cc b/chrome/browser/chromeos/fileapi/file_system_backend_unittest.cc
index f163faf..761f41a 100644
--- a/chrome/browser/chromeos/fileapi/file_system_backend_unittest.cc
+++ b/chrome/browser/chromeos/fileapi/file_system_backend_unittest.cc
@@ -101,7 +101,7 @@ TEST(ChromeOSFileSystemBackendTest, GetRootDirectories) {
}
TEST(ChromeOSFileSystemBackendTest, AccessPermissions) {
- url::AddStandardScheme("chrome-extension");
+ url::AddStandardScheme("chrome-extension", url::SCHEME_WITHOUT_PORT);
scoped_refptr<storage::ExternalMountPoints> mount_points(
storage::ExternalMountPoints::CreateRefCounted());
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index bc33c62..c577edf 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -506,21 +506,33 @@ void ChromeContentClient::AddPepperPlugins(
#endif // defined(ENABLE_PLUGINS)
}
+#if defined(OS_CHROMEOS)
+static const int kNumChromeStandardURLSchemes = 6;
+#else
+static const int kNumChromeStandardURLSchemes = 5;
+#endif
+static const url::SchemeWithType kChromeStandardURLSchemes[
+ kNumChromeStandardURLSchemes] = {
+ {extensions::kExtensionScheme, url::SCHEME_WITHOUT_PORT},
+ {chrome::kChromeNativeScheme, url::SCHEME_WITHOUT_PORT},
+ {extensions::kExtensionResourceScheme, url::SCHEME_WITHOUT_PORT},
+ {chrome::kChromeSearchScheme, url::SCHEME_WITHOUT_PORT},
+ {dom_distiller::kDomDistillerScheme, url::SCHEME_WITHOUT_PORT},
+#if defined(OS_CHROMEOS)
+ {chrome::kCrosScheme, url::SCHEME_WITHOUT_PORT},
+#endif
+};
+
void ChromeContentClient::AddAdditionalSchemes(
- std::vector<std::string>* standard_schemes,
+ std::vector<url::SchemeWithType>* standard_schemes,
std::vector<std::string>* savable_schemes) {
- standard_schemes->push_back(extensions::kExtensionScheme);
+ for (int i = 0; i < kNumChromeStandardURLSchemes; i++)
+ standard_schemes->push_back(kChromeStandardURLSchemes[i]);
+
savable_schemes->push_back(extensions::kExtensionScheme);
- standard_schemes->push_back(chrome::kChromeNativeScheme);
- standard_schemes->push_back(extensions::kExtensionResourceScheme);
savable_schemes->push_back(extensions::kExtensionResourceScheme);
- standard_schemes->push_back(chrome::kChromeSearchScheme);
savable_schemes->push_back(chrome::kChromeSearchScheme);
- standard_schemes->push_back(dom_distiller::kDomDistillerScheme);
savable_schemes->push_back(dom_distiller::kDomDistillerScheme);
-#if defined(OS_CHROMEOS)
- standard_schemes->push_back(chrome::kCrosScheme);
-#endif
}
std::string ChromeContentClient::GetProduct() const {
diff --git a/chrome/common/chrome_content_client.h b/chrome/common/chrome_content_client.h
index 0b5d516..dab975b 100644
--- a/chrome/common/chrome_content_client.h
+++ b/chrome/common/chrome_content_client.h
@@ -16,6 +16,8 @@
#include "content/public/common/pepper_plugin_info.h"
#endif
+#include "url/url_util.h"
+
// Returns the user agent of Chrome.
std::string GetUserAgent();
@@ -54,7 +56,7 @@ class ChromeContentClient : public content::ContentClient {
void SetGpuInfo(const gpu::GPUInfo& gpu_info) override;
void AddPepperPlugins(
std::vector<content::PepperPluginInfo>* plugins) override;
- void AddAdditionalSchemes(std::vector<std::string>* standard_schemes,
+ void AddAdditionalSchemes(std::vector<url::SchemeWithType>* standard_schemes,
std::vector<std::string>* saveable_shemes) override;
std::string GetProduct() const override;
std::string GetUserAgent() const override;
diff --git a/chrome/common/chrome_content_client_ios.mm b/chrome/common/chrome_content_client_ios.mm
index 48a448d..bfca613 100644
--- a/chrome/common/chrome_content_client_ios.mm
+++ b/chrome/common/chrome_content_client_ios.mm
@@ -12,6 +12,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "url/gurl.h"
+#include "url/url_util.h"
// TODO(ios): Investigate merging with chrome_content_client.cc; this would
// requiring either a lot of ifdefing, or spliting the file into parts.
@@ -30,7 +31,7 @@ void ChromeContentClient::AddPepperPlugins(
}
void ChromeContentClient::AddAdditionalSchemes(
- std::vector<std::string>* standard_schemes,
+ std::vector<url::SchemeWithType>* standard_schemes,
std::vector<std::string>* saveable_shemes) {
// No additional schemes for iOS.
}
diff --git a/chrome/common/chrome_content_client_unittest.cc b/chrome/common/chrome_content_client_unittest.cc
index 5fa08bf..62591a9 100644
--- a/chrome/common/chrome_content_client_unittest.cc
+++ b/chrome/common/chrome_content_client_unittest.cc
@@ -4,12 +4,18 @@
#include "chrome/common/chrome_content_client.h"
+#include <string.h>
+
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/strings/string_split.h"
#include "content/public/common/content_switches.h"
+#include "extensions/common/constants.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+#include "url/url_util.h"
namespace {
@@ -121,4 +127,16 @@ TEST(ChromeContentClientTest, FindMostRecent) {
}
#endif // defined(ENABLE_PLUGINS)
+TEST(ChromeContentClientTest, AdditionalSchemes) {
+ EXPECT_TRUE(url::IsStandard(
+ extensions::kExtensionScheme,
+ url::Component(0, strlen(extensions::kExtensionScheme))));
+
+ GURL extension_url(
+ "chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef/foo.html");
+ url::Origin origin(extension_url);
+ EXPECT_EQ("chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef",
+ origin.Serialize());
+}
+
} // namespace chrome_common
diff --git a/components/test/run_all_unittests.cc b/components/test/run_all_unittests.cc
index 572eb6f..9edbe9c 100644
--- a/components/test/run_all_unittests.cc
+++ b/components/test/run_all_unittests.cc
@@ -78,10 +78,10 @@ class ComponentsTestSuite : public base::TestSuite {
// These schemes need to be added globally to pass tests of
// autocomplete_input_unittest.cc and content_settings_pattern*
- url::AddStandardScheme("chrome");
- url::AddStandardScheme("chrome-extension");
- url::AddStandardScheme("chrome-devtools");
- url::AddStandardScheme("chrome-search");
+ url::AddStandardScheme("chrome", url::SCHEME_WITHOUT_PORT);
+ url::AddStandardScheme("chrome-extension", url::SCHEME_WITHOUT_PORT);
+ url::AddStandardScheme("chrome-devtools", url::SCHEME_WITHOUT_PORT);
+ url::AddStandardScheme("chrome-search", url::SCHEME_WITHOUT_PORT);
// Not using kExtensionScheme to avoid the dependency to extensions.
ContentSettingsPattern::SetNonWildcardDomainNonPortScheme(
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index 00677c5..e37b410 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -75,8 +75,8 @@ class SiteInstanceTest : public testing::Test {
void SetUp() override {
old_browser_client_ = SetBrowserClientForTesting(&browser_client_);
- url::AddStandardScheme(kPrivilegedScheme);
- url::AddStandardScheme(kChromeUIScheme);
+ url::AddStandardScheme(kPrivilegedScheme, url::SCHEME_WITHOUT_PORT);
+ url::AddStandardScheme(kChromeUIScheme, url::SCHEME_WITHOUT_PORT);
SiteInstanceImpl::set_render_process_host_factory(&rph_factory_);
}
diff --git a/content/common/url_schemes.cc b/content/common/url_schemes.cc
index c65bb14..26fee93 100644
--- a/content/common/url_schemes.cc
+++ b/content/common/url_schemes.cc
@@ -19,8 +19,8 @@
namespace {
-void AddStandardSchemeHelper(const std::string& scheme) {
- url::AddStandardScheme(scheme.c_str());
+void AddStandardSchemeHelper(const url::SchemeWithType& scheme) {
+ url::AddStandardScheme(scheme.scheme, scheme.type);
}
} // namespace
@@ -28,15 +28,15 @@ void AddStandardSchemeHelper(const std::string& scheme) {
namespace content {
void RegisterContentSchemes(bool lock_standard_schemes) {
- std::vector<std::string> additional_standard_schemes;
+ std::vector<url::SchemeWithType> additional_standard_schemes;
std::vector<std::string> additional_savable_schemes;
GetContentClient()->AddAdditionalSchemes(&additional_standard_schemes,
&additional_savable_schemes);
- url::AddStandardScheme(kChromeDevToolsScheme);
- url::AddStandardScheme(kChromeUIScheme);
- url::AddStandardScheme(kGuestScheme);
- url::AddStandardScheme(kMetadataScheme);
+ url::AddStandardScheme(kChromeDevToolsScheme, url::SCHEME_WITHOUT_PORT);
+ url::AddStandardScheme(kChromeUIScheme, url::SCHEME_WITHOUT_PORT);
+ url::AddStandardScheme(kGuestScheme, url::SCHEME_WITHOUT_PORT);
+ url::AddStandardScheme(kMetadataScheme, url::SCHEME_WITHOUT_AUTHORITY);
std::for_each(additional_standard_schemes.begin(),
additional_standard_schemes.end(),
AddStandardSchemeHelper);
diff --git a/content/public/common/content_client.h b/content/public/common/content_client.h
index 89887e0..94d8d7d 100644
--- a/content/public/common/content_client.h
+++ b/content/public/common/content_client.h
@@ -15,6 +15,7 @@
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "ui/base/layout.h"
+#include "url/url_util.h"
class GURL;
@@ -89,7 +90,7 @@ class CONTENT_EXPORT ContentClient {
// Gives the embedder a chance to register its own standard and saveable
// url schemes early on in the startup sequence.
virtual void AddAdditionalSchemes(
- std::vector<std::string>* standard_schemes,
+ std::vector<url::SchemeWithType>* standard_schemes,
std::vector<std::string>* savable_schemes) {}
// Returns whether the given message should be sent in a swapped out renderer.
diff --git a/extensions/shell/common/shell_content_client.cc b/extensions/shell/common/shell_content_client.cc
index 1879a8f..946fe83 100644
--- a/extensions/shell/common/shell_content_client.cc
+++ b/extensions/shell/common/shell_content_client.cc
@@ -74,12 +74,20 @@ void ShellContentClient::AddPepperPlugins(
#endif // !defined(DISABLE_NACL)
}
+static const int kNumShellStandardURLSchemes = 2;
+static const url::SchemeWithType kShellStandardURLSchemes[
+ kNumShellStandardURLSchemes] = {
+ {extensions::kExtensionScheme, url::SCHEME_WITHOUT_PORT},
+ {extensions::kExtensionResourceScheme, url::SCHEME_WITHOUT_PORT},
+};
+
void ShellContentClient::AddAdditionalSchemes(
- std::vector<std::string>* standard_schemes,
+ std::vector<url::SchemeWithType>* standard_schemes,
std::vector<std::string>* savable_schemes) {
- standard_schemes->push_back(kExtensionScheme);
+ for (int i = 0; i < kNumShellStandardURLSchemes; i++)
+ standard_schemes->push_back(kShellStandardURLSchemes[i]);
+
savable_schemes->push_back(kExtensionScheme);
- standard_schemes->push_back(kExtensionResourceScheme);
savable_schemes->push_back(kExtensionResourceScheme);
}
diff --git a/extensions/shell/common/shell_content_client.h b/extensions/shell/common/shell_content_client.h
index 4e0e384..f105511 100644
--- a/extensions/shell/common/shell_content_client.h
+++ b/extensions/shell/common/shell_content_client.h
@@ -8,6 +8,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "content/public/common/content_client.h"
+#include "url/url_util.h"
namespace extensions {
@@ -18,7 +19,7 @@ class ShellContentClient : public content::ContentClient {
void AddPepperPlugins(
std::vector<content::PepperPluginInfo>* plugins) override;
- void AddAdditionalSchemes(std::vector<std::string>* standard_schemes,
+ void AddAdditionalSchemes(std::vector<url::SchemeWithType>* standard_schemes,
std::vector<std::string>* saveable_shemes) override;
std::string GetUserAgent() const override;
base::string16 GetLocalizedString(int message_id) const override;
diff --git a/extensions/test/extensions_unittests_main.cc b/extensions/test/extensions_unittests_main.cc
index aa0108f..f39e40d 100644
--- a/extensions/test/extensions_unittests_main.cc
+++ b/extensions/test/extensions_unittests_main.cc
@@ -16,9 +16,17 @@
#include "third_party/mojo/src/mojo/edk/embedder/test_embedder.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gl/test/gl_surface_test_support.h"
+#include "url/url_util.h"
namespace {
+const int kNumExtensionStandardURLSchemes = 2;
+const url::SchemeWithType kExtensionStandardURLSchemes[
+ kNumExtensionStandardURLSchemes] = {
+ {extensions::kExtensionScheme, url::SCHEME_WITHOUT_PORT},
+ {extensions::kExtensionResourceScheme, url::SCHEME_WITHOUT_PORT},
+};
+
// Content client that exists only to register chrome-extension:// scheme with
// the url module.
// TODO(jamescook): Should this be merged with ShellContentClient? Should this
@@ -30,11 +38,12 @@ class ExtensionsContentClient : public content::ContentClient {
// content::ContentClient overrides:
void AddAdditionalSchemes(
- std::vector<std::string>* standard_schemes,
+ std::vector<url::SchemeWithType>* standard_schemes,
std::vector<std::string>* savable_schemes) override {
- standard_schemes->push_back(extensions::kExtensionScheme);
+ for (int i = 0; i < kNumExtensionStandardURLSchemes; i++)
+ standard_schemes->push_back(kExtensionStandardURLSchemes[i]);
+
savable_schemes->push_back(extensions::kExtensionScheme);
- standard_schemes->push_back(extensions::kExtensionResourceScheme);
savable_schemes->push_back(extensions::kExtensionResourceScheme);
}
diff --git a/google_apis/drive/drive_api_url_generator_unittest.cc b/google_apis/drive/drive_api_url_generator_unittest.cc
index 1ccae2f..9643dea 100644
--- a/google_apis/drive/drive_api_url_generator_unittest.cc
+++ b/google_apis/drive/drive_api_url_generator_unittest.cc
@@ -62,7 +62,7 @@ TEST_F(DriveApiUrlGeneratorTest, GetFilesGetUrl) {
url_generator_.GetFilesGetUrl("0ADK06pfg", true, GURL()).spec());
// If |embed_origin| is not empty, it should be added as a query parameter.
- url::AddStandardScheme("chrome-extension");
+ url::AddStandardScheme("chrome-extension", url::SCHEME_WITHOUT_PORT);
EXPECT_EQ(
"https://www.example.com/drive/v2/files/0ADK06pfg"
"?embedOrigin=chrome-extension%3A%2F%2Ftest",
diff --git a/ios/chrome/test/ios_chrome_unit_test_suite.cc b/ios/chrome/test/ios_chrome_unit_test_suite.cc
index 53e9425..eb1886f 100644
--- a/ios/chrome/test/ios_chrome_unit_test_suite.cc
+++ b/ios/chrome/test/ios_chrome_unit_test_suite.cc
@@ -75,7 +75,8 @@ void IOSChromeUnitTestSuite::Initialize() {
{
ios::TestChromeBrowserProvider provider;
- url::AddStandardScheme(provider.GetChromeUIScheme());
+ url::AddStandardScheme(provider.GetChromeUIScheme(),
+ url::SCHEME_WITHOUT_PORT);
}
base::TestSuite::Initialize();
diff --git a/mojo/runner/url_resolver.cc b/mojo/runner/url_resolver.cc
index 3ae8bc0..4222ec7 100644
--- a/mojo/runner/url_resolver.cc
+++ b/mojo/runner/url_resolver.cc
@@ -17,7 +17,7 @@ namespace runner {
URLResolver::URLResolver() {
// Needed to treat first component of mojo URLs as host, not path.
- url::AddStandardScheme("mojo");
+ url::AddStandardScheme("mojo", url::SCHEME_WITHOUT_AUTHORITY);
}
URLResolver::~URLResolver() {
diff --git a/url/scheme_host_port.cc b/url/scheme_host_port.cc
index c2fe830..9c12295 100644
--- a/url/scheme_host_port.cc
+++ b/url/scheme_host_port.cc
@@ -7,6 +7,7 @@
#include <string.h>
#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "url/gurl.h"
#include "url/url_canon.h"
@@ -16,25 +17,21 @@
namespace url {
-SchemeHostPort::SchemeHostPort() : port_(0) {
-}
+namespace {
-SchemeHostPort::SchemeHostPort(base::StringPiece scheme,
- base::StringPiece host,
- uint16 port)
- : scheme_(scheme.data(), scheme.length()),
- host_(host.data(), host.length()),
- port_(port) {
- // Try to canonicalize the host (copy/pasted from net/base. :( ).
- const url::Component raw_host_component(0, static_cast<int>(host.length()));
+bool IsCanonicalHost(const base::StringPiece& host) {
std::string canon_host;
- url::StdStringCanonOutput canon_host_output(&canon_host);
- url::CanonHostInfo host_info;
- url::CanonicalizeHostVerbose(host.data(), raw_host_component,
- &canon_host_output, &host_info);
+
+ // Try to canonicalize the host (copy/pasted from net/base. :( ).
+ const Component raw_host_component(0,
+ base::checked_cast<int>(host.length()));
+ StdStringCanonOutput canon_host_output(&canon_host);
+ CanonHostInfo host_info;
+ CanonicalizeHostVerbose(host.data(), raw_host_component,
+ &canon_host_output, &host_info);
if (host_info.out_host.is_nonempty() &&
- host_info.family != url::CanonHostInfo::BROKEN) {
+ host_info.family != CanonHostInfo::BROKEN) {
// Success! Assert that there's no extra garbage.
canon_host_output.Complete();
DCHECK_EQ(host_info.out_host.len, static_cast<int>(canon_host.length()));
@@ -43,44 +40,95 @@ SchemeHostPort::SchemeHostPort(base::StringPiece scheme,
canon_host.clear();
}
- // Return an invalid SchemeHostPort object if any of the following conditions
- // hold:
- //
- // 1. The provided scheme is non-standard, 'blob:', or 'filesystem:'.
- // 2. The provided host is non-canonical.
- // 3. The scheme is 'file' and the port is non-zero.
- // 4. The scheme is not 'file', and the port is zero or the host is empty.
- bool isUnsupportedScheme =
- !url::IsStandard(scheme.data(),
- url::Component(0, static_cast<int>(scheme.length()))) ||
- scheme == kFileSystemScheme || scheme == kBlobScheme;
- bool isNoncanonicalHost = host != canon_host;
- bool isFileSchemeWithPort = scheme == kFileScheme && port != 0;
- bool isNonFileSchemeWithoutPortOrHost =
- scheme != kFileScheme && (port == 0 || host.empty());
- if (isUnsupportedScheme || isNoncanonicalHost || isFileSchemeWithPort ||
- isNonFileSchemeWithoutPortOrHost) {
- scheme_.clear();
- host_.clear();
- port_ = 0;
- }
+ return host == canon_host;
}
-SchemeHostPort::SchemeHostPort(const GURL& url) : port_(0) {
- if (!url.is_valid() || !url.IsStandard())
- return;
+bool IsValidInput(const base::StringPiece& scheme,
+ const base::StringPiece& host,
+ uint16 port) {
+ SchemeType scheme_type = SCHEME_WITH_PORT;
+ bool is_standard = GetStandardSchemeType(
+ scheme.data(),
+ Component(0, base::checked_cast<int>(scheme.length())),
+ &scheme_type);
+ if (!is_standard)
+ return false;
// These schemes do not follow the generic URL syntax, so we treat them as
// invalid (scheme, host, port) tuples (even though such URLs' _Origin_ might
// have a (scheme, host, port) tuple, they themselves do not).
- if (url.SchemeIsBlob() || url.SchemeIsFileSystem())
+ if (scheme == kFileSystemScheme || scheme == kBlobScheme)
+ return false;
+
+ switch (scheme_type) {
+ case SCHEME_WITH_PORT:
+ // A URL with |scheme| is required to have the host and port (may be
+ // omitted in a serialization if it's the same as the default value).
+ // Return an invalid instance if either of them is not given.
+ if (host.empty() || port == 0)
+ return false;
+
+ if (!IsCanonicalHost(host))
+ return false;
+
+ return true;
+
+ case SCHEME_WITHOUT_PORT:
+ if (port != 0) {
+ // Return an invalid object if a URL with the scheme never represents
+ // the port data but the given |port| is non-zero.
+ return false;
+ }
+
+ if (!IsCanonicalHost(host))
+ return false;
+
+ return true;
+
+ case SCHEME_WITHOUT_AUTHORITY:
+ return false;
+
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+} // namespace
+
+SchemeHostPort::SchemeHostPort() : port_(0) {
+}
+
+SchemeHostPort::SchemeHostPort(base::StringPiece scheme,
+ base::StringPiece host,
+ uint16 port)
+ : port_(0) {
+ if (!IsValidInput(scheme, host, port))
return;
- scheme_ = url.scheme();
- host_ = url.host();
- port_ = url.EffectiveIntPort() == url::PORT_UNSPECIFIED
- ? 0
- : url.EffectiveIntPort();
+ scheme.CopyToString(&scheme_);
+ host.CopyToString(&host_);
+ port_ = port;
+}
+
+SchemeHostPort::SchemeHostPort(const GURL& url) : port_(0) {
+ if (!url.is_valid())
+ return;
+
+ const std::string& scheme = url.scheme();
+ const std::string& host = url.host();
+
+ // A valid GURL never returns PORT_INVALID.
+ int port = url.EffectiveIntPort();
+ if (port == PORT_UNSPECIFIED)
+ port = 0;
+
+ if (!IsValidInput(scheme, host, port))
+ return;
+
+ scheme_ = scheme;
+ host_ = host;
+ port_ = port;
}
SchemeHostPort::~SchemeHostPort() {
@@ -95,15 +143,20 @@ std::string SchemeHostPort::Serialize() const {
if (IsInvalid())
return result;
- bool is_default_port =
- port_ == url::DefaultPortForScheme(scheme_.data(),
- static_cast<int>(scheme_.length()));
-
result.append(scheme_);
result.append(kStandardSchemeSeparator);
result.append(host_);
- if (scheme_ != kFileScheme && !is_default_port) {
+ if (port_ == 0)
+ return result;
+
+ // Omit the port component if the port matches with the default port
+ // defined for the scheme, if any.
+ int default_port = DefaultPortForScheme(scheme_.data(),
+ static_cast<int>(scheme_.length()));
+ if (default_port == PORT_UNSPECIFIED)
+ return result;
+ if (port_ != default_port) {
result.push_back(':');
result.append(base::IntToString(port_));
}
diff --git a/url/scheme_host_port.h b/url/scheme_host_port.h
index 2cc9e07..6e35a25 100644
--- a/url/scheme_host_port.h
+++ b/url/scheme_host_port.h
@@ -36,20 +36,19 @@ namespace url {
// schemes such as "blob", "filesystem", "data", and "javascript" can only be
// represented as invalid SchemeHostPort objects.
//
-// * The "file" scheme follows the standard syntax, but it is important to note
-// that the authority portion (host, port) is optional. URLs without an
-// authority portion will be represented with an empty string for the host,
-// and a port of 0 (e.g. "file:///etc/hosts" => ("file", "", 0)), and URLs
-// with a host-only authority portion will be represented with a port of 0
-// (e.g. "file://example.com/etc/hosts" => ("file", "example.com", 0)). See
-// Section 3 of RFC 3986 to better understand these constructs.
+// * For example, the "file" scheme follows the standard syntax, but it is
+// important to note that the authority portion (host, port) is optional.
+// URLs without an authority portion will be represented with an empty string
+// for the host, and a port of 0 (e.g. "file:///etc/hosts" =>
+// ("file", "", 0)), and URLs with a host-only authority portion will be
+// represented with a port of 0 (e.g. "file://example.com/etc/hosts" =>
+// ("file", "example.com", 0)). See Section 3 of RFC 3986 to better understand
+// these constructs.
//
// * SchemeHostPort has no notion of the Origin concept (RFC 6454), and in
// particular, it has no notion of a "unique" Origin. If you need to take
// uniqueness into account (and, if you're making security-relevant decisions
-// then you absolutely do), please use 'url::Origin' instead[1].
-//
-// [1]: // TODO(mkwst): Land 'url::Origin'. :)
+// then you absolutely do), please use 'url::Origin' instead.
//
// Usage:
//
diff --git a/url/url_util.cc b/url/url_util.cc
index 279ab7e..21bf3cc 100644
--- a/url/url_util.cc
+++ b/url/url_util.cc
@@ -19,21 +19,24 @@ namespace url {
namespace {
const int kNumStandardURLSchemes = 8;
-const char* kStandardURLSchemes[kNumStandardURLSchemes] = {
- kHttpScheme,
- kHttpsScheme,
- kFileScheme, // Yes, file URLs can have a hostname!
- kFtpScheme,
- kGopherScheme,
- kWsScheme, // WebSocket.
- kWssScheme, // WebSocket secure.
- kFileSystemScheme,
+const SchemeWithType kStandardURLSchemes[kNumStandardURLSchemes] = {
+ {kHttpScheme, SCHEME_WITH_PORT},
+ {kHttpsScheme, SCHEME_WITH_PORT},
+ // Yes, file URLs can have a hostname, so file URLs should be handled as
+ // "standard". File URLs never have a port as specified by the SchemeType
+ // field.
+ {kFileScheme, SCHEME_WITHOUT_PORT},
+ {kFtpScheme, SCHEME_WITH_PORT},
+ {kGopherScheme, SCHEME_WITH_PORT},
+ {kWsScheme, SCHEME_WITH_PORT}, // WebSocket.
+ {kWssScheme, SCHEME_WITH_PORT}, // WebSocket secure.
+ {kFileSystemScheme, SCHEME_WITHOUT_AUTHORITY},
};
// List of the currently installed standard schemes. This list is lazily
// initialized by InitStandardSchemes and is leaked on shutdown to prevent
// any destructors from being called that will slow us down or cause problems.
-std::vector<const char*>* standard_schemes = NULL;
+std::vector<SchemeWithType>* standard_schemes = NULL;
// See the LockStandardSchemes declaration in the header.
bool standard_schemes_locked = false;
@@ -54,7 +57,7 @@ template<> struct CharToStringPiece<base::char16> {
void InitStandardSchemes() {
if (standard_schemes)
return;
- standard_schemes = new std::vector<const char*>;
+ standard_schemes = new std::vector<SchemeWithType>;
for (int i = 0; i < kNumStandardURLSchemes; i++)
standard_schemes->push_back(kStandardURLSchemes[i]);
}
@@ -73,10 +76,13 @@ inline bool DoCompareSchemeComponent(const CHAR* spec,
compare_to);
}
-// Returns true if the given scheme identified by |scheme| within |spec| is one
-// of the registered "standard" schemes.
+// Returns true and sets |type| to the SchemeType of the given scheme
+// identified by |scheme| within |spec| if the scheme is one of the registered
+// "standard" schemes.
template<typename CHAR>
-bool DoIsStandard(const CHAR* spec, const Component& scheme) {
+bool DoIsStandard(const CHAR* spec,
+ const Component& scheme,
+ SchemeType* type) {
if (!scheme.is_nonempty())
return false; // Empty or invalid schemes are non-standard.
@@ -85,8 +91,10 @@ bool DoIsStandard(const CHAR* spec, const Component& scheme) {
if (base::LowerCaseEqualsASCII(
typename CharToStringPiece<CHAR>::Piece(
&spec[scheme.begin], scheme.len),
- standard_schemes->at(i)))
+ standard_schemes->at(i).scheme)) {
+ *type = standard_schemes->at(i).type;
return true;
+ }
}
return false;
}
@@ -156,6 +164,7 @@ bool DoCanonicalize(const CHAR* in_spec,
// This is the parsed version of the input URL, we have to canonicalize it
// before storing it in our object.
bool success;
+ SchemeType unused_scheme_type = SCHEME_WITH_PORT;
if (DoCompareSchemeComponent(spec, scheme, url::kFileScheme)) {
// File URLs are special.
ParseFileURL(spec, spec_len, &parsed_input);
@@ -168,7 +177,7 @@ bool DoCanonicalize(const CHAR* in_spec,
charset_converter, output,
output_parsed);
- } else if (DoIsStandard(spec, scheme)) {
+ } else if (DoIsStandard(spec, scheme, &unused_scheme_type)) {
// All "normal" URLs.
ParseStandardURL(spec, spec_len, &parsed_input);
success = CanonicalizeStandardURL(spec, spec_len, parsed_input,
@@ -217,9 +226,10 @@ bool DoResolveRelative(const char* base_spec,
base_is_hierarchical = num_slashes > 0;
}
+ SchemeType unused_scheme_type = SCHEME_WITH_PORT;
bool standard_base_scheme =
base_parsed.scheme.is_nonempty() &&
- DoIsStandard(base_spec, base_parsed.scheme);
+ DoIsStandard(base_spec, base_parsed.scheme, &unused_scheme_type);
bool is_relative;
Component relative_component;
@@ -340,7 +350,8 @@ bool DoReplaceComponents(const char* spec,
return ReplaceFileSystemURL(spec, parsed, replacements, charset_converter,
output, out_parsed);
}
- if (DoIsStandard(spec, parsed.scheme)) {
+ SchemeType unused_scheme_type = SCHEME_WITH_PORT;
+ if (DoIsStandard(spec, parsed.scheme, &unused_scheme_type)) {
return ReplaceStandardURL(spec, parsed, replacements, charset_converter,
output, out_parsed);
}
@@ -365,7 +376,8 @@ void Shutdown() {
}
}
-void AddStandardScheme(const char* new_scheme) {
+void AddStandardScheme(const char* new_scheme,
+ SchemeType type) {
// If this assert triggers, it means you've called AddStandardScheme after
// LockStandardSchemes have been called (see the header file for
// LockStandardSchemes for more).
@@ -388,7 +400,10 @@ void AddStandardScheme(const char* new_scheme) {
memcpy(dup_scheme, new_scheme, scheme_len + 1);
InitStandardSchemes();
- standard_schemes->push_back(dup_scheme);
+ SchemeWithType scheme_with_type;
+ scheme_with_type.scheme = dup_scheme;
+ scheme_with_type.type = type;
+ standard_schemes->push_back(scheme_with_type);
}
void LockStandardSchemes() {
@@ -396,11 +411,19 @@ void LockStandardSchemes() {
}
bool IsStandard(const char* spec, const Component& scheme) {
- return DoIsStandard(spec, scheme);
+ SchemeType unused_scheme_type;
+ return DoIsStandard(spec, scheme, &unused_scheme_type);
+}
+
+bool GetStandardSchemeType(const char* spec,
+ const Component& scheme,
+ SchemeType* type) {
+ return DoIsStandard(spec, scheme, type);
}
bool IsStandard(const base::char16* spec, const Component& scheme) {
- return DoIsStandard(spec, scheme);
+ SchemeType unused_scheme_type;
+ return DoIsStandard(spec, scheme, &unused_scheme_type);
}
bool FindAndCompareScheme(const char* str,
diff --git a/url/url_util.h b/url/url_util.h
index 5817044..36e7814 100644
--- a/url/url_util.h
+++ b/url/url_util.h
@@ -37,6 +37,25 @@ URL_EXPORT void Shutdown();
// Schemes --------------------------------------------------------------------
+// Types of a scheme representing the requirements on the data represented by
+// the authority component of a URL with the scheme.
+enum URL_EXPORT SchemeType {
+ // The authority component of a URL with the scheme, if any, has the port
+ // (the default values may be omitted in a serialization).
+ SCHEME_WITH_PORT,
+ // The authority component of a URL with the scheme, if any, doesn't have a
+ // port.
+ SCHEME_WITHOUT_PORT,
+ // A URL with the scheme doesn't have the authority component.
+ SCHEME_WITHOUT_AUTHORITY,
+};
+
+// A pair for representing a standard scheme name and the SchemeType for it.
+struct URL_EXPORT SchemeWithType {
+ const char* scheme;
+ SchemeType type;
+};
+
// Adds an application-defined scheme to the internal list of "standard-format"
// URL schemes. A standard-format scheme adheres to what RFC 3986 calls "generic
// URI syntax" (https://tools.ietf.org/html/rfc3986#section-3).
@@ -44,7 +63,8 @@ URL_EXPORT void Shutdown();
// This function is not threadsafe and can not be called concurrently with any
// other url_util function. It will assert if the list of standard schemes has
// been locked (see LockStandardSchemes).
-URL_EXPORT void AddStandardScheme(const char* new_scheme);
+URL_EXPORT void AddStandardScheme(const char* new_scheme,
+ SchemeType scheme_type);
// Sets a flag to prevent future calls to AddStandardScheme from succeeding.
//
@@ -87,11 +107,18 @@ inline bool FindAndCompareScheme(const base::string16& str,
compare, found_scheme);
}
-// Returns true if the given string represents a URL whose scheme is in the list
-// of known standard-format schemes (see AddStandardScheme).
+// Returns true if the given scheme identified by |scheme| within |spec| is in
+// the list of known standard-format schemes (see AddStandardScheme).
URL_EXPORT bool IsStandard(const char* spec, const Component& scheme);
URL_EXPORT bool IsStandard(const base::char16* spec, const Component& scheme);
+// Returns true and sets |type| to the SchemeType of the given scheme
+// identified by |scheme| within |spec| if the scheme is in the list of known
+// standard-format schemes (see AddStandardScheme).
+URL_EXPORT bool GetStandardSchemeType(const char* spec,
+ const Component& scheme,
+ SchemeType* type);
+
// URL library wrappers -------------------------------------------------------
// Parses the given spec according to the extracted scheme type. Normal users
diff --git a/url/url_util_unittest.cc b/url/url_util_unittest.cc
index 9297765..b89bfa1 100644
--- a/url/url_util_unittest.cc
+++ b/url/url_util_unittest.cc
@@ -61,6 +61,38 @@ TEST(URLUtilTest, FindAndCompareScheme) {
EXPECT_TRUE(found_scheme == Component(1, 11));
}
+TEST(URLUtilTest, IsStandard) {
+ const char kHTTPScheme[] = "http";
+ EXPECT_TRUE(IsStandard(kHTTPScheme, Component(0, strlen(kHTTPScheme))));
+
+ const char kFooScheme[] = "foo";
+ EXPECT_FALSE(IsStandard(kFooScheme, Component(0, strlen(kFooScheme))));
+}
+
+TEST(URLUtilTest, GetStandardSchemeType) {
+ url::SchemeType scheme_type;
+
+ const char kHTTPScheme[] = "http";
+ scheme_type = url::SCHEME_WITHOUT_AUTHORITY;
+ EXPECT_TRUE(GetStandardSchemeType(kHTTPScheme,
+ Component(0, strlen(kHTTPScheme)),
+ &scheme_type));
+ EXPECT_EQ(url::SCHEME_WITH_PORT, scheme_type);
+
+ const char kFilesystemScheme[] = "filesystem";
+ scheme_type = url::SCHEME_WITH_PORT;
+ EXPECT_TRUE(GetStandardSchemeType(kFilesystemScheme,
+ Component(0, strlen(kFilesystemScheme)),
+ &scheme_type));
+ EXPECT_EQ(url::SCHEME_WITHOUT_AUTHORITY, scheme_type);
+
+ const char kFooScheme[] = "foo";
+ scheme_type = url::SCHEME_WITH_PORT;
+ EXPECT_FALSE(GetStandardSchemeType(kFooScheme,
+ Component(0, strlen(kFooScheme)),
+ &scheme_type));
+}
+
TEST(URLUtilTest, ReplaceComponents) {
Parsed parsed;
RawCanonOutputT<char> output;
@@ -220,7 +252,7 @@ TEST(URLUtilTest, TestEncodeURIComponent) {
}
TEST(URLUtilTest, TestResolveRelativeWithNonStandardBase) {
- // This tests non-standard (in the sense that GIsStandard() == false)
+ // This tests non-standard (in the sense that IsStandard() == false)
// hierarchical schemes.
struct ResolveRelativeCase {
const char* base;