| Index: content/common/content_security_policy/csp_source_unittest.cc
|
| diff --git a/content/common/content_security_policy/csp_source_unittest.cc b/content/common/content_security_policy/csp_source_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..eebce0fb18e1deaf9a153989fdb4cf6e4b6d0e92
|
| --- /dev/null
|
| +++ b/content/common/content_security_policy/csp_source_unittest.cc
|
| @@ -0,0 +1,388 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "content/common/content_security_policy/csp_context.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace content {
|
| +
|
| +TEST(CSPSourceTest, ParseScheme) {
|
| + // Empty scheme.
|
| + EXPECT_FALSE(CSPSource::Parse(":"));
|
| +
|
| + // First character is alpha/non-alpha.
|
| + EXPECT_TRUE(CSPSource::Parse("a:"));
|
| + EXPECT_FALSE(CSPSource::Parse("1ab:"));
|
| + EXPECT_FALSE(CSPSource::Parse("-:"));
|
| +
|
| + // Remaining characters.
|
| + EXPECT_TRUE(CSPSource::Parse("abcd:"));
|
| + EXPECT_TRUE(CSPSource::Parse("a123:"));
|
| + EXPECT_TRUE(CSPSource::Parse("a+-:"));
|
| + EXPECT_TRUE(CSPSource::Parse("a1+-:"));
|
| +
|
| + // Case sensitivity.
|
| + EXPECT_TRUE(CSPSource::Parse("HTTP:"));
|
| + EXPECT_TRUE(CSPSource::Parse("a-a:"));
|
| + EXPECT_TRUE(CSPSource::Parse("A-B:"));
|
| +}
|
| +
|
| +TEST(CSPSourceTest, ParseHost) {
|
| + // Wildcards.
|
| + EXPECT_TRUE(CSPSource::Parse("*"));
|
| + EXPECT_FALSE(CSPSource::Parse("*."));
|
| + EXPECT_TRUE(CSPSource::Parse("*.a"));
|
| + EXPECT_FALSE(CSPSource::Parse("a.*"));
|
| + EXPECT_FALSE(CSPSource::Parse("a.*.b"));
|
| +
|
| + // Dot-separation.
|
| + EXPECT_TRUE(CSPSource::Parse("a"));
|
| + EXPECT_TRUE(CSPSource::Parse("a.b.c"));
|
| + EXPECT_FALSE(CSPSource::Parse("a.b."));
|
| + EXPECT_FALSE(CSPSource::Parse(".b.c"));
|
| + EXPECT_FALSE(CSPSource::Parse("a..c"));
|
| +
|
| + // Valid/Invalid characters.
|
| + EXPECT_TRUE(CSPSource::Parse("az09-"));
|
| + EXPECT_FALSE(CSPSource::Parse("+"));
|
| +
|
| + // Strange host.
|
| + // REVIEW(arthursonzogni): Is that correct?
|
| + EXPECT_TRUE(CSPSource::Parse("---.com"));
|
| +}
|
| +
|
| +TEST(CSPSourceTest, ParsePort) {
|
| + // Common case.
|
| + EXPECT_TRUE(CSPSource::Parse("a:80"));
|
| + EXPECT_EQ(CSPSource::Parse("a:80")->port, 80);
|
| + EXPECT_EQ(CSPSource::Parse("a:80")->is_port_wildcard, false);
|
| +
|
| + // Empty port.
|
| + EXPECT_TRUE(CSPSource::Parse("a"));
|
| + EXPECT_EQ(CSPSource::Parse("a")->port, url::PORT_UNSPECIFIED);
|
| + EXPECT_EQ(CSPSource::Parse("a")->is_port_wildcard, false);
|
| +
|
| + // Wildcard port.
|
| + EXPECT_TRUE(CSPSource::Parse("a:*"));
|
| + EXPECT_EQ(CSPSource::Parse("a:*")->port, url::PORT_UNSPECIFIED);
|
| + EXPECT_EQ(CSPSource::Parse("a:*")->is_port_wildcard, true);
|
| +
|
| + // Leading zeroes.
|
| + EXPECT_TRUE(CSPSource::Parse("a:000"));
|
| + EXPECT_TRUE(CSPSource::Parse("a:0"));
|
| +
|
| + // Invalid chars.
|
| + EXPECT_FALSE(CSPSource::Parse("a:-1"));
|
| + EXPECT_FALSE(CSPSource::Parse("a:+1"));
|
| + EXPECT_FALSE(CSPSource::Parse("a: 1"));
|
| +}
|
| +
|
| +TEST(CSPSourceTest, ParsePath) {
|
| + EXPECT_TRUE(CSPSource::Parse("a.com/path"));
|
| + EXPECT_TRUE(CSPSource::Parse("a.com/path/"));
|
| + EXPECT_TRUE(CSPSource::Parse("*/path"));
|
| +
|
| + EXPECT_EQ(CSPSource::Parse("a.com/path/to/file")->path, "/path/to/file");
|
| + EXPECT_EQ(CSPSource::Parse("a.com/path/to/dir/")->path, "/path/to/dir/");
|
| +
|
| + EXPECT_EQ(CSPSource::Parse("host/query?url=9999")->path, "/query");
|
| + EXPECT_EQ(CSPSource::Parse("host/query#fragment")->path, "/query");
|
| + EXPECT_EQ(CSPSource::Parse("host/Hello%20G%C3%BCnter")->path,
|
| + "/Hello Günter");
|
| +}
|
| +
|
| +TEST(CSPSourceTest, Parse) {
|
| + // host
|
| + EXPECT_TRUE(CSPSource::Parse("host.com"));
|
| +
|
| + // host/path
|
| + EXPECT_TRUE(CSPSource::Parse("host.com/path"));
|
| +
|
| + // scheme:
|
| + EXPECT_TRUE(CSPSource::Parse("http:"));
|
| + EXPECT_FALSE(CSPSource::Parse("0000:"));
|
| +
|
| + // scheme://(.*)
|
| + EXPECT_TRUE(CSPSource::Parse("http://host.com"));
|
| + EXPECT_FALSE(CSPSource::Parse("http:/host.com"));
|
| + EXPECT_FALSE(CSPSource::Parse("http://"));
|
| +
|
| + // scheme://host/path
|
| + EXPECT_TRUE(CSPSource::Parse("http://host.com/path"));
|
| +
|
| + // host:port/path
|
| + EXPECT_TRUE(CSPSource::Parse("http://host.com:80/path"));
|
| + EXPECT_FALSE(CSPSource::Parse("http://host.com:xx/path"));
|
| +
|
| + // host:port
|
| + EXPECT_TRUE(CSPSource::Parse("http://host.com:80"));
|
| + EXPECT_FALSE(CSPSource::Parse("http://host.com:xx"));
|
| +
|
| + // Special URL:
|
| + EXPECT_FALSE(CSPSource::Parse("about:blank"));
|
| +}
|
| +
|
| +TEST(CSPSourceTest, AllowScheme) {
|
| + CSPContext context;
|
| +
|
| + // http -> { http, https}.
|
| + {
|
| + CSPSource source("http", "", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("ftp://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("ws://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("wss://a.com")));
|
| + }
|
| +
|
| + // ws -> { ws, wss}.
|
| + {
|
| + CSPSource source("ws", "", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("https://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("ftp://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("ws://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("wss://a.com")));
|
| + }
|
| +
|
| + // Exact matches required (ftp)
|
| + {
|
| + CSPSource source("ftp", "", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("ftp://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com")));
|
| + }
|
| +
|
| + // Exact matches required (https)
|
| + {
|
| + CSPSource source("https", "", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com")));
|
| + }
|
| +
|
| + // Exact matches required (wss)
|
| + {
|
| + CSPSource source("wss", "", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("wss://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("ws://a.com")));
|
| + }
|
| +
|
| + // Scheme is empty (ProtocolMatchesSelf).
|
| + {
|
| + CSPSource source("", "a.com", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com")));
|
| +
|
| + // Self's scheme is http.
|
| + context.SetSelf(url::Origin(GURL("http://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http-so://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https-so://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("ftp://a.com")));
|
| +
|
| + // Self's is https.
|
| + context.SetSelf(url::Origin(GURL("https://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http-so://a.com")));
|
| + // REVIEW(): Is it the correct behavior?
|
| + EXPECT_FALSE(source.Allow(&context, GURL("https-so://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("ftp://a.com")));
|
| +
|
| + // Self's scheme is not in the http familly.
|
| + context.SetSelf(url::Origin(GURL("ftp://a.com/")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("ftp://a.com")));
|
| +
|
| + // Self's scheme is unique.
|
| + context.SetSelf(url::Origin(GURL("non-standard-scheme://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("non-standard-scheme://a.com")));
|
| + }
|
| +}
|
| +
|
| +TEST(CSPSourceTest, AllowHost) {
|
| + CSPContext context;
|
| + context.SetSelf(url::Origin(GURL("http://example.com")));
|
| +
|
| + // Host is * (source-expression = "http://*")
|
| + {
|
| + CSPSource source("http", "", true, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://.")));
|
| + }
|
| +
|
| + // Host is *.foo.bar
|
| + {
|
| + CSPSource source("", "foo.bar", true, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://bar")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://foo.bar")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://o.bar")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://*.foo.bar")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://sub.foo.bar")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://sub.sub.foo.bar")));
|
| + // FOR-REVIEWER: strange case?
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://.foo.bar")));
|
| + }
|
| +
|
| + // Host is exact.
|
| + {
|
| + CSPSource source("", "foo.bar", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://foo.bar")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://sub.foo.bar")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://bar")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://.foo.bar")));
|
| + }
|
| +}
|
| +
|
| +TEST(CSPSourceTest, AllowPort) {
|
| + CSPContext context;
|
| + context.SetSelf(url::Origin(GURL("http://example.com")));
|
| +
|
| + // Source's port unspecified.
|
| + {
|
| + CSPSource source("", "a.com", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com:80")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com:8080")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com:443")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("https://a.com:80")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("https://a.com:8080")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https://a.com:443")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("unknown://a.com:80")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com")));
|
| + }
|
| +
|
| + // Source's port is "*".
|
| + {
|
| + CSPSource source("", "a.com", false, url::PORT_UNSPECIFIED, true, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com:80")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com:8080")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https://a.com:8080")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https://a.com:0")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https://a.com")));
|
| + }
|
| +
|
| + // Source has a port.
|
| + {
|
| + CSPSource source("", "a.com", false, 80, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com:80")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com:8080")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https://a.com")));
|
| + }
|
| +
|
| + // Allow upgrade from :80 to :443
|
| + {
|
| + CSPSource source("", "a.com", false, 80, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("https://a.com:443")));
|
| + // REVIEW(arthursonzogni): Is it expected?
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com:443")));
|
| + }
|
| +
|
| + // Host is * but port is specified
|
| + {
|
| + CSPSource source("http", "", true, 111, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com:111")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com:222")));
|
| + }
|
| +}
|
| +
|
| +TEST(CSPSourceTest, AllowPath) {
|
| + CSPContext context;
|
| + context.SetSelf(url::Origin(GURL("http://example.com")));
|
| +
|
| + // Path to a file
|
| + {
|
| + CSPSource source("", "a.com", false, url::PORT_UNSPECIFIED, false,
|
| + "/path/to/file");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/path/to/file")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com/path/to/")));
|
| + EXPECT_FALSE(
|
| + source.Allow(&context, GURL("http://a.com/path/to/something")));
|
| + }
|
| +
|
| + // Path to a directory
|
| + {
|
| + CSPSource source("", "a.com", false, url::PORT_UNSPECIFIED, false,
|
| + "/path/to/");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/path/to/file")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/path/to/")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com/path/")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com/path/to")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com/path/to")));
|
| + }
|
| +
|
| + // Empty path
|
| + {
|
| + CSPSource source("", "a.com", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/path/to/file")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/path/to/")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com")));
|
| + }
|
| +
|
| + // Almost empty path
|
| + {
|
| + CSPSource source("", "a.com", false, url::PORT_UNSPECIFIED, false, "/");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/path/to/file")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/path/to/")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com")));
|
| + }
|
| +
|
| + // Path encoded.
|
| + {
|
| + CSPSource source("http", "a.com", false, url::PORT_UNSPECIFIED, false,
|
| + "/Hello Günter");
|
| + EXPECT_TRUE(
|
| + source.Allow(&context, GURL("http://a.com/Hello%20G%C3%BCnter")));
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/Hello Günter")));
|
| + }
|
| +
|
| + // Host is * but path is specified.
|
| + {
|
| + CSPSource source("http", "", true, url::PORT_UNSPECIFIED, false,
|
| + "/allowed-path");
|
| + EXPECT_TRUE(source.Allow(&context, GURL("http://a.com/allowed-path")));
|
| + EXPECT_FALSE(source.Allow(&context, GURL("http://a.com/disallowed-path")));
|
| + }
|
| +}
|
| +
|
| +TEST(CSPSourceTest, ToString) {
|
| + {
|
| + CSPSource source("http", "", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_EQ("http", source.ToString());
|
| + }
|
| + {
|
| + CSPSource source("http", "a.com", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_EQ("http://a.com", source.ToString());
|
| + }
|
| + {
|
| + CSPSource source("", "a.com", false, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_EQ("a.com", source.ToString());
|
| + }
|
| + {
|
| + CSPSource source("", "a.com", true, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_EQ("*.a.com", source.ToString());
|
| + }
|
| + {
|
| + CSPSource source("", "", true, url::PORT_UNSPECIFIED, false, "");
|
| + EXPECT_EQ("*", source.ToString());
|
| + }
|
| + {
|
| + CSPSource source("", "a.com", false, 80, false, "");
|
| + EXPECT_EQ("a.com:80", source.ToString());
|
| + }
|
| + {
|
| + CSPSource source("", "a.com", false, url::PORT_UNSPECIFIED, true, "");
|
| + EXPECT_EQ("a.com:*", source.ToString());
|
| + }
|
| + {
|
| + CSPSource source("", "a.com", false, url::PORT_UNSPECIFIED, false, "/path");
|
| + EXPECT_EQ("a.com/path", source.ToString());
|
| + }
|
| +}
|
| +
|
| +} // namespace content
|
|
|