Commit 048bee10 authored by csharrison's avatar csharrison Committed by Commit bot

Add url::Origin::GetURL() to convert Origins to URLs without reparsing

The previous canonical way to convert an Origin to a GURL was
to call GURL(origin.Serialize()). This is expensive and often in the
critical path of user perceived page loads. One such caller has
been converted to the new method, and the rest will be converted
in a followup patch.

BUG=651554

Review-Url: https://codereview.chromium.org/2378323003
Cr-Commit-Position: refs/heads/master@{#422613}
parent 5d1bf66e
...@@ -4096,7 +4096,7 @@ void RenderFrameImpl::willSendRequest(blink::WebLocalFrame* frame, ...@@ -4096,7 +4096,7 @@ void RenderFrameImpl::willSendRequest(blink::WebLocalFrame* frame,
extra_data->set_render_frame_id(routing_id_); extra_data->set_render_frame_id(routing_id_);
extra_data->set_is_main_frame(!parent); extra_data->set_is_main_frame(!parent);
extra_data->set_frame_origin( extra_data->set_frame_origin(
blink::WebStringToGURL(frame->document().getSecurityOrigin().toString())); url::Origin(frame->document().getSecurityOrigin()).GetURL());
extra_data->set_parent_is_main_frame(parent && !parent->parent()); extra_data->set_parent_is_main_frame(parent && !parent->parent());
extra_data->set_parent_render_frame_id(parent_routing_id); extra_data->set_parent_render_frame_id(parent_routing_id);
extra_data->set_allow_download( extra_data->set_allow_download(
......
...@@ -65,6 +65,16 @@ std::string Origin::Serialize() const { ...@@ -65,6 +65,16 @@ std::string Origin::Serialize() const {
return tuple_.Serialize(); return tuple_.Serialize();
} }
GURL Origin::GetURL() const {
if (unique())
return GURL();
if (scheme() == kFileScheme)
return GURL("file:///");
return tuple_.GetURL();
}
bool Origin::IsSameOriginWith(const Origin& other) const { bool Origin::IsSameOriginWith(const Origin& other) const {
if (unique_ || other.unique_) if (unique_ || other.unique_)
return false; return false;
......
...@@ -122,6 +122,14 @@ class URL_EXPORT Origin { ...@@ -122,6 +122,14 @@ class URL_EXPORT Origin {
return IsSameOriginWith(other); return IsSameOriginWith(other);
} }
// Efficiently returns what GURL(Serialize()) would without re-parsing the
// URL. This can be used for the (rare) times a GURL representation is needed
// for an Origin.
// Note: The returned URL will not necessarily be serialized to the same value
// as the Origin would. The GURL will have an added "/" path for Origins with
// valid SchemeHostPorts and file Origins.
GURL GetURL() const;
// Same as GURL::DomainIs. If |this| origin is unique, then returns false. // Same as GURL::DomainIs. If |this| origin is unique, then returns false.
bool DomainIs(base::StringPiece lower_ascii_domain) const; bool DomainIs(base::StringPiece lower_ascii_domain) const;
......
...@@ -13,6 +13,26 @@ ...@@ -13,6 +13,26 @@
namespace { namespace {
void ExpectParsedComponentEqual(const url::Component& a,
const url::Component& b) {
EXPECT_EQ(a.begin, b.begin);
EXPECT_EQ(a.len, b.len);
}
void ExpectParsedUrlsEqual(const GURL& a, const GURL& b) {
EXPECT_EQ(a, b);
const url::Parsed& a_parsed = a.parsed_for_possibly_invalid_spec();
const url::Parsed& b_parsed = b.parsed_for_possibly_invalid_spec();
ExpectParsedComponentEqual(a_parsed.scheme, b_parsed.scheme);
ExpectParsedComponentEqual(a_parsed.username, b_parsed.username);
ExpectParsedComponentEqual(a_parsed.password, b_parsed.password);
ExpectParsedComponentEqual(a_parsed.host, b_parsed.host);
ExpectParsedComponentEqual(a_parsed.port, b_parsed.port);
ExpectParsedComponentEqual(a_parsed.path, b_parsed.path);
ExpectParsedComponentEqual(a_parsed.query, b_parsed.query);
ExpectParsedComponentEqual(a_parsed.ref, b_parsed.ref);
}
TEST(OriginTest, UniqueOriginComparison) { TEST(OriginTest, UniqueOriginComparison) {
url::Origin unique_origin; url::Origin unique_origin;
EXPECT_EQ("", unique_origin.scheme()); EXPECT_EQ("", unique_origin.scheme());
...@@ -38,6 +58,8 @@ TEST(OriginTest, UniqueOriginComparison) { ...@@ -38,6 +58,8 @@ TEST(OriginTest, UniqueOriginComparison) {
EXPECT_FALSE(origin.IsSameOriginWith(origin)); EXPECT_FALSE(origin.IsSameOriginWith(origin));
EXPECT_FALSE(unique_origin.IsSameOriginWith(origin)); EXPECT_FALSE(unique_origin.IsSameOriginWith(origin));
EXPECT_FALSE(origin.IsSameOriginWith(unique_origin)); EXPECT_FALSE(origin.IsSameOriginWith(unique_origin));
ExpectParsedUrlsEqual(GURL(origin.Serialize()), origin.GetURL());
} }
} }
...@@ -103,6 +125,8 @@ TEST(OriginTest, ConstructFromGURL) { ...@@ -103,6 +125,8 @@ TEST(OriginTest, ConstructFromGURL) {
EXPECT_TRUE(origin.IsSameOriginWith(origin)); EXPECT_TRUE(origin.IsSameOriginWith(origin));
EXPECT_FALSE(different_origin.IsSameOriginWith(origin)); EXPECT_FALSE(different_origin.IsSameOriginWith(origin));
EXPECT_FALSE(origin.IsSameOriginWith(different_origin)); EXPECT_FALSE(origin.IsSameOriginWith(different_origin));
ExpectParsedUrlsEqual(GURL(origin.Serialize()), origin.GetURL());
} }
} }
...@@ -127,7 +151,10 @@ TEST(OriginTest, Serialization) { ...@@ -127,7 +151,10 @@ TEST(OriginTest, Serialization) {
GURL url(test_case.url); GURL url(test_case.url);
EXPECT_TRUE(url.is_valid()); EXPECT_TRUE(url.is_valid());
url::Origin origin(url); url::Origin origin(url);
EXPECT_EQ(test_case.expected, origin.Serialize()); std::string serialized = origin.Serialize();
ExpectParsedUrlsEqual(GURL(serialized), origin.GetURL());
EXPECT_EQ(test_case.expected, serialized);
// The '<<' operator should produce the same serialization as Serialize(). // The '<<' operator should produce the same serialization as Serialize().
std::stringstream out; std::stringstream out;
...@@ -186,6 +213,8 @@ TEST(OriginTest, UnsafelyCreate) { ...@@ -186,6 +213,8 @@ TEST(OriginTest, UnsafelyCreate) {
EXPECT_EQ(test.port, origin.port()); EXPECT_EQ(test.port, origin.port());
EXPECT_FALSE(origin.unique()); EXPECT_FALSE(origin.unique());
EXPECT_TRUE(origin.IsSameOriginWith(origin)); EXPECT_TRUE(origin.IsSameOriginWith(origin));
ExpectParsedUrlsEqual(GURL(origin.Serialize()), origin.GetURL());
} }
} }
...@@ -221,6 +250,8 @@ TEST(OriginTest, UnsafelyCreateUniqueOnInvalidInput) { ...@@ -221,6 +250,8 @@ TEST(OriginTest, UnsafelyCreateUniqueOnInvalidInput) {
EXPECT_EQ(0, origin.port()); EXPECT_EQ(0, origin.port());
EXPECT_TRUE(origin.unique()); EXPECT_TRUE(origin.unique());
EXPECT_FALSE(origin.IsSameOriginWith(origin)); EXPECT_FALSE(origin.IsSameOriginWith(origin));
ExpectParsedUrlsEqual(GURL(origin.Serialize()), origin.GetURL());
} }
} }
...@@ -249,6 +280,8 @@ TEST(OriginTest, UnsafelyCreateUniqueViaEmbeddedNulls) { ...@@ -249,6 +280,8 @@ TEST(OriginTest, UnsafelyCreateUniqueViaEmbeddedNulls) {
EXPECT_EQ(0, origin.port()); EXPECT_EQ(0, origin.port());
EXPECT_TRUE(origin.unique()); EXPECT_TRUE(origin.unique());
EXPECT_FALSE(origin.IsSameOriginWith(origin)); EXPECT_FALSE(origin.IsSameOriginWith(origin));
ExpectParsedUrlsEqual(GURL(origin.Serialize()), origin.GetURL());
} }
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "url/gurl.h" #include "url/gurl.h"
#include "url/third_party/mozilla/url_parse.h"
#include "url/url_canon.h" #include "url/url_canon.h"
#include "url/url_canon_stdstring.h" #include "url/url_canon_stdstring.h"
#include "url/url_constants.h" #include "url/url_constants.h"
...@@ -142,12 +143,46 @@ bool SchemeHostPort::IsInvalid() const { ...@@ -142,12 +143,46 @@ bool SchemeHostPort::IsInvalid() const {
} }
std::string SchemeHostPort::Serialize() const { std::string SchemeHostPort::Serialize() const {
// Null checking for |parsed| in SerializeInternal is probably slower than
// just filling it in and discarding it here.
url::Parsed parsed;
return SerializeInternal(&parsed);
}
GURL SchemeHostPort::GetURL() const {
url::Parsed parsed;
std::string serialized = SerializeInternal(&parsed);
// If the serialized string is passed to GURL for parsing, it will append an
// empty path "/". Add that here. Note: per RFC 6454 we cannot do this for
// normal Origin serialization.
DCHECK(!parsed.path.is_valid());
parsed.path = Component(serialized.length(), 1);
serialized.append("/");
return GURL(std::move(serialized), parsed, true);
}
bool SchemeHostPort::Equals(const SchemeHostPort& other) const {
return port_ == other.port() && scheme_ == other.scheme() &&
host_ == other.host();
}
bool SchemeHostPort::operator<(const SchemeHostPort& other) const {
return std::tie(port_, scheme_, host_) <
std::tie(other.port_, other.scheme_, other.host_);
}
std::string SchemeHostPort::SerializeInternal(url::Parsed* parsed) const {
std::string result; std::string result;
if (IsInvalid()) if (IsInvalid())
return result; return result;
parsed->scheme = Component(0, scheme_.length());
result.append(scheme_); result.append(scheme_);
result.append(kStandardSchemeSeparator); result.append(kStandardSchemeSeparator);
parsed->host = Component(result.length(), host_.length());
result.append(host_); result.append(host_);
if (port_ == 0) if (port_ == 0)
...@@ -161,20 +196,12 @@ std::string SchemeHostPort::Serialize() const { ...@@ -161,20 +196,12 @@ std::string SchemeHostPort::Serialize() const {
return result; return result;
if (port_ != default_port) { if (port_ != default_port) {
result.push_back(':'); result.push_back(':');
result.append(base::UintToString(port_)); std::string port(base::UintToString(port_));
parsed->port = Component(result.length(), port.length());
result.append(std::move(port));
} }
return result; return result;
} }
bool SchemeHostPort::Equals(const SchemeHostPort& other) const {
return port_ == other.port() && scheme_ == other.scheme() &&
host_ == other.host();
}
bool SchemeHostPort::operator<(const SchemeHostPort& other) const {
return std::tie(port_, scheme_, host_) <
std::tie(other.port_, other.scheme_, other.host_);
}
} // namespace url } // namespace url
...@@ -16,6 +16,8 @@ class GURL; ...@@ -16,6 +16,8 @@ class GURL;
namespace url { namespace url {
struct Parsed;
// This class represents a (scheme, host, port) tuple extracted from a URL. // This class represents a (scheme, host, port) tuple extracted from a URL.
// //
// The primary purpose of this class is to represent relevant network-authority // The primary purpose of this class is to represent relevant network-authority
...@@ -111,6 +113,10 @@ class URL_EXPORT SchemeHostPort { ...@@ -111,6 +113,10 @@ class URL_EXPORT SchemeHostPort {
// serialized as a unique Origin. // serialized as a unique Origin.
std::string Serialize() const; std::string Serialize() const;
// Efficiently returns what GURL(Serialize()) would return, without needing to
// re-parse the URL.
GURL GetURL() const;
// Two SchemeHostPort objects are "equal" iff their schemes, hosts, and ports // Two SchemeHostPort objects are "equal" iff their schemes, hosts, and ports
// are exact matches. // are exact matches.
// //
...@@ -124,6 +130,8 @@ class URL_EXPORT SchemeHostPort { ...@@ -124,6 +130,8 @@ class URL_EXPORT SchemeHostPort {
bool operator<(const SchemeHostPort& other) const; bool operator<(const SchemeHostPort& other) const;
private: private:
std::string SerializeInternal(url::Parsed* parsed) const;
std::string scheme_; std::string scheme_;
std::string host_; std::string host_;
uint16_t port_; uint16_t port_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment