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 |