summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/public/common/common_param_traits.cc37
-rw-r--r--content/public/common/common_param_traits.h9
-rw-r--r--tools/ipc_fuzzer/fuzzer/fuzzer.cc22
-rw-r--r--url/origin.cc13
-rw-r--r--url/origin.h18
-rw-r--r--url/origin_unittest.cc91
-rw-r--r--url/scheme_host_port.cc29
-rw-r--r--url/scheme_host_port_unittest.cc62
8 files changed, 271 insertions, 10 deletions
diff --git a/content/public/common/common_param_traits.cc b/content/public/common/common_param_traits.cc
index 6415d1e..fd103b9 100644
--- a/content/public/common/common_param_traits.cc
+++ b/content/public/common/common_param_traits.cc
@@ -81,6 +81,43 @@ void ParamTraits<url::DeprecatedSerializedOrigin>::Log(
l->append(p.string());
}
+void ParamTraits<url::Origin>::Write(Message* m, const url::Origin& p) {
+ WriteParam(m, p.unique());
+ WriteParam(m, p.scheme());
+ WriteParam(m, p.host());
+ WriteParam(m, p.port());
+}
+
+bool ParamTraits<url::Origin>::Read(const Message* m,
+ base::PickleIterator* iter,
+ url::Origin* p) {
+ bool unique;
+ std::string scheme;
+ std::string host;
+ uint16 port;
+ if (!ReadParam(m, iter, &unique) || !ReadParam(m, iter, &scheme) ||
+ !ReadParam(m, iter, &host) || !ReadParam(m, iter, &port)) {
+ *p = url::Origin();
+ return false;
+ }
+
+ *p = unique ? url::Origin()
+ : url::Origin::UnsafelyCreateOriginWithoutNormalization(
+ scheme, host, port);
+
+ // If a unique origin was created, but the unique flag wasn't set, then
+ // the values provided to 'UnsafelyCreateOriginWithoutNormalization' were
+ // invalid; kill the renderer.
+ if (!unique && p->unique())
+ return false;
+
+ return true;
+}
+
+void ParamTraits<url::Origin>::Log(const url::Origin& p, std::string* l) {
+ l->append(p.Serialize());
+}
+
void ParamTraits<net::HostPortPair>::Write(Message* m, const param_type& p) {
WriteParam(m, p.host());
WriteParam(m, p.port());
diff --git a/content/public/common/common_param_traits.h b/content/public/common/common_param_traits.h
index 3d0ae9f..804c4f2c 100644
--- a/content/public/common/common_param_traits.h
+++ b/content/public/common/common_param_traits.h
@@ -24,6 +24,7 @@
#include "ui/surface/transport_dib.h"
#include "url/deprecated_serialized_origin.h"
#include "url/gurl.h"
+#include "url/origin.h"
namespace content {
class PageState;
@@ -52,6 +53,14 @@ struct CONTENT_EXPORT ParamTraits<url::DeprecatedSerializedOrigin> {
static void Log(const param_type& p, std::string* l);
};
+template <>
+struct CONTENT_EXPORT ParamTraits<url::Origin> {
+ typedef url::Origin param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, base::PickleIterator* iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
template<>
struct CONTENT_EXPORT ParamTraits<net::HostPortPair> {
typedef net::HostPortPair param_type;
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer.cc b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
index 2af05d9..f0676ae 100644
--- a/tools/ipc_fuzzer/fuzzer/fuzzer.cc
+++ b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
@@ -1790,6 +1790,28 @@ struct FuzzTraits<ui::LatencyInfo::InputCoordinate> {
};
template <>
+struct FuzzTraits<url::Origin> {
+ static bool Fuzz(url::Origin* p, Fuzzer* fuzzer) {
+ std::string scheme = p->scheme();
+ std::string host = p->host();
+ uint16 port = p->port();
+ if (!FuzzParam(&scheme, fuzzer))
+ return false;
+ if (!FuzzParam(&host, fuzzer))
+ return false;
+ if (!FuzzParam(&port, fuzzer))
+ return false;
+ *p = url::Origin::UnsafelyCreateOriginWithoutNormalization(scheme, host,
+ port);
+
+ // Force a unique origin 1% of the time:
+ if (RandInRange(100) == 1)
+ *p = url::Origin();
+ return true;
+ }
+};
+
+template <>
struct FuzzTraits<url::DeprecatedSerializedOrigin> {
static bool Fuzz(url::DeprecatedSerializedOrigin* p, Fuzzer* fuzzer) {
std::string origin = p->string();
diff --git a/url/origin.cc b/url/origin.cc
index e80eb72..7b8d805 100644
--- a/url/origin.cc
+++ b/url/origin.cc
@@ -38,9 +38,22 @@ Origin::Origin(const GURL& url) : unique_(true) {
unique_ = tuple_.IsInvalid();
}
+Origin::Origin(base::StringPiece scheme, base::StringPiece host, uint16 port)
+ : tuple_(scheme, host, port) {
+ unique_ = tuple_.IsInvalid();
+}
+
Origin::~Origin() {
}
+// static
+Origin Origin::UnsafelyCreateOriginWithoutNormalization(
+ base::StringPiece scheme,
+ base::StringPiece host,
+ uint16 port) {
+ return Origin(scheme, host, port);
+}
+
std::string Origin::Serialize() const {
if (unique())
return "null";
diff --git a/url/origin.h b/url/origin.h
index 01703ef..3746de9 100644
--- a/url/origin.h
+++ b/url/origin.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
#include "url/scheme_host_port.h"
#include "url/third_party/mozilla/url_parse.h"
#include "url/url_canon.h"
@@ -86,6 +87,19 @@ class URL_EXPORT Origin {
// 3. 'file' URLs all parse as ("file", "", 0).
explicit Origin(const GURL& url);
+ // Creates an Origin from a |scheme|, |host|, and |port|. All the parameters
+ // must be valid and canonicalized. In particular, note that this cannot be
+ // used to create unique origins; 'url::Origin()' is the right way to do that.
+ //
+ // This constructor should be used in order to pass 'Origin' objects back and
+ // forth over IPC (as transitioning through GURL would risk potentially
+ // dangerous recanonicalization); other potential callers should prefer the
+ // 'GURL'-based constructor.
+ static Origin UnsafelyCreateOriginWithoutNormalization(
+ base::StringPiece scheme,
+ base::StringPiece host,
+ uint16 port);
+
~Origin();
// For unique origins, these return ("", "", 0).
@@ -108,10 +122,10 @@ class URL_EXPORT Origin {
bool operator<(const Origin& other) const;
private:
+ Origin(base::StringPiece scheme, base::StringPiece host, uint16 port);
+
SchemeHostPort tuple_;
bool unique_;
-
- DISALLOW_COPY_AND_ASSIGN(Origin);
};
URL_EXPORT std::ostream& operator<<(std::ostream& out,
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc
index a774c62..ec4ec65 100644
--- a/url/origin_unittest.cc
+++ b/url/origin_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/logging.h"
#include "url/origin.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -157,4 +158,94 @@ TEST(OriginTest, Comparison) {
}
}
+TEST(OriginTest, UnsafelyCreate) {
+ struct TestCase {
+ const char* scheme;
+ const char* host;
+ uint16 port;
+ } cases[] = {
+ {"http", "example.com", 80},
+ {"http", "example.com", 123},
+ {"https", "example.com", 443},
+ {"https", "example.com", 123},
+ {"file", "", 0},
+ {"file", "example.com", 0},
+ };
+
+ for (const auto& test : cases) {
+ SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
+ << test.port);
+ url::Origin origin = url::Origin::UnsafelyCreateOriginWithoutNormalization(
+ test.scheme, test.host, test.port);
+ EXPECT_EQ(test.scheme, origin.scheme());
+ EXPECT_EQ(test.host, origin.host());
+ EXPECT_EQ(test.port, origin.port());
+ EXPECT_FALSE(origin.unique());
+ EXPECT_TRUE(origin.IsSameOriginWith(origin));
+ }
+}
+
+TEST(OriginTest, UnsafelyCreateUniqueOnInvalidInput) {
+ struct TestCases {
+ const char* scheme;
+ const char* host;
+ uint16 port;
+ } cases[] = {{"", "", 0},
+ {"data", "", 0},
+ {"blob", "", 0},
+ {"filesystem", "", 0},
+ {"data", "example.com", 80},
+ {"http", "☃.net", 80},
+ {"http\nmore", "example.com", 80},
+ {"http\rmore", "example.com", 80},
+ {"http\n", "example.com", 80},
+ {"http\r", "example.com", 80},
+ {"http", "example.com\nnot-example.com", 80},
+ {"http", "example.com\rnot-example.com", 80},
+ {"http", "example.com\n", 80},
+ {"http", "example.com\r", 80},
+ {"http", "example.com", 0},
+ {"file", "", 80}};
+
+ for (const auto& test : cases) {
+ SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
+ << test.port);
+ url::Origin origin = url::Origin::UnsafelyCreateOriginWithoutNormalization(
+ test.scheme, test.host, test.port);
+ EXPECT_EQ("", origin.scheme());
+ EXPECT_EQ("", origin.host());
+ EXPECT_EQ(0, origin.port());
+ EXPECT_TRUE(origin.unique());
+ EXPECT_FALSE(origin.IsSameOriginWith(origin));
+ }
+}
+
+TEST(OriginTest, UnsafelyCreateUniqueViaEmbeddedNulls) {
+ struct TestCases {
+ const char* scheme;
+ size_t scheme_length;
+ const char* host;
+ size_t host_length;
+ uint16 port;
+ } cases[] = {{"http\0more", 9, "example.com", 11, 80},
+ {"http\0", 5, "example.com", 11, 80},
+ {"\0http", 5, "example.com", 11, 80},
+ {"http", 4, "example.com\0not-example.com", 27, 80},
+ {"http", 4, "example.com\0", 12, 80},
+ {"http", 4, "\0example.com", 12, 80}};
+
+ for (const auto& test : cases) {
+ SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
+ << test.port);
+ url::Origin origin = url::Origin::UnsafelyCreateOriginWithoutNormalization(
+ std::string(test.scheme, test.scheme_length),
+ std::string(test.host, test.host_length), test.port);
+ EXPECT_EQ("", origin.scheme());
+ EXPECT_EQ("", origin.host());
+ EXPECT_EQ(0, origin.port());
+ EXPECT_TRUE(origin.unique());
+ EXPECT_FALSE(origin.IsSameOriginWith(origin));
+ }
+}
+
} // namespace url
diff --git a/url/scheme_host_port.cc b/url/scheme_host_port.cc
index cb2d5cc..c2fe830 100644
--- a/url/scheme_host_port.cc
+++ b/url/scheme_host_port.cc
@@ -25,10 +25,6 @@ SchemeHostPort::SchemeHostPort(base::StringPiece scheme,
: scheme_(scheme.data(), scheme.length()),
host_(host.data(), host.length()),
port_(port) {
-#if DCHECK_IS_ON()
- DCHECK(url::IsStandard(scheme.data(),
- url::Component(0, static_cast<int>(scheme.length()))));
-
// Try to canonicalize the host (copy/pasted from net/base. :( ).
const url::Component raw_host_component(0, static_cast<int>(host.length()));
std::string canon_host;
@@ -46,11 +42,28 @@ SchemeHostPort::SchemeHostPort(base::StringPiece scheme,
// Empty host, or canonicalization failed.
canon_host.clear();
}
- DCHECK_EQ(host, canon_host);
- DCHECK(scheme == kFileScheme ? port == 0 : port != 0);
- DCHECK(!host.empty() || port == 0);
-#endif
+ // 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;
+ }
}
SchemeHostPort::SchemeHostPort(const GURL& url) : port_(0) {
diff --git a/url/scheme_host_port_unittest.cc b/url/scheme_host_port_unittest.cc
index 3001d24..817631d 100644
--- a/url/scheme_host_port_unittest.cc
+++ b/url/scheme_host_port_unittest.cc
@@ -62,6 +62,68 @@ TEST(SchemeHostPortTest, ExplicitConstruction) {
}
}
+TEST(SchemeHostPortTest, InvalidConstruction) {
+ struct TestCases {
+ const char* scheme;
+ const char* host;
+ uint16 port;
+ } cases[] = {{"", "", 0},
+ {"data", "", 0},
+ {"blob", "", 0},
+ {"filesystem", "", 0},
+ {"http", "", 80},
+ {"data", "example.com", 80},
+ {"http", "☃.net", 80},
+ {"http\nmore", "example.com", 80},
+ {"http\rmore", "example.com", 80},
+ {"http\n", "example.com", 80},
+ {"http\r", "example.com", 80},
+ {"http", "example.com\nnot-example.com", 80},
+ {"http", "example.com\rnot-example.com", 80},
+ {"http", "example.com\n", 80},
+ {"http", "example.com\r", 80},
+ {"http", "example.com", 0},
+ {"file", "", 80}};
+
+ for (const auto& test : cases) {
+ SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
+ << test.port);
+ url::SchemeHostPort tuple(test.scheme, test.host, test.port);
+ EXPECT_EQ("", tuple.scheme());
+ EXPECT_EQ("", tuple.host());
+ EXPECT_EQ(0, tuple.port());
+ EXPECT_TRUE(tuple.IsInvalid());
+ EXPECT_TRUE(tuple.Equals(tuple));
+ }
+}
+
+TEST(SchemeHostPortTest, InvalidConstructionWithEmbeddedNulls) {
+ struct TestCases {
+ const char* scheme;
+ size_t scheme_length;
+ const char* host;
+ size_t host_length;
+ uint16 port;
+ } cases[] = {{"http\0more", 9, "example.com", 11, 80},
+ {"http\0", 5, "example.com", 11, 80},
+ {"\0http", 5, "example.com", 11, 80},
+ {"http", 4, "example.com\0not-example.com", 27, 80},
+ {"http", 4, "example.com\0", 12, 80},
+ {"http", 4, "\0example.com", 12, 80}};
+
+ for (const auto& test : cases) {
+ SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
+ << test.port);
+ url::SchemeHostPort tuple(std::string(test.scheme, test.scheme_length),
+ std::string(test.host, test.host_length),
+ test.port);
+ EXPECT_EQ("", tuple.scheme());
+ EXPECT_EQ("", tuple.host());
+ EXPECT_EQ(0, tuple.port());
+ EXPECT_TRUE(tuple.IsInvalid());
+ }
+}
+
TEST(SchemeHostPortTest, GURLConstruction) {
struct TestCases {
const char* url;