Commit c008bf65 authored by Devlin Cronin's avatar Devlin Cronin Committed by Commit Bot

[Extensions] Support IPv6 in URLPatterns

Add IPv6 support to match patterns (URLPatterns). This is most necessary
for implementing activeTab support on IPv6 addresses, and will also be
needed for runtime host permissions.

Bug: 853064
Change-Id: I0ac1980af679476c17112137575d37ad77490dcc
Reviewed-on: https://chromium-review.googlesource.com/1102118Reviewed-by: default avatarIstiaque Ahmed <lazyboy@chromium.org>
Commit-Queue: Devlin <rdevlin.cronin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568278}
parent d20bf68d
......@@ -261,16 +261,35 @@ URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern,
base::StringPiece host_and_port =
pattern.substr(host_start_pos, host_end_pos - host_start_pos);
// Ports are only valid with standard (and non-file) schemes.
base::StringPiece host_piece;
size_t port_pos = host_and_port.find(':');
if (port_pos != base::StringPiece::npos &&
!SetPort(host_and_port.substr(port_pos + 1))) {
size_t port_separator_pos = base::StringPiece::npos;
if (host_and_port[0] != '[') {
// Not IPv6 (either IPv4 or just a normal address).
port_separator_pos = host_and_port.find(':');
} else { // IPv6.
size_t host_end_pos = host_and_port.find(']');
if (host_end_pos == base::StringPiece::npos)
return PARSE_ERROR_INVALID_HOST;
if (host_end_pos == 1)
return PARSE_ERROR_EMPTY_HOST;
if (host_end_pos < host_and_port.length() - 1) {
// The host isn't the only component. Check for a port. This would
// require a ':' to follow the closing ']' from the host.
if (host_and_port[host_end_pos + 1] != ':')
return PARSE_ERROR_INVALID_HOST;
port_separator_pos = host_end_pos + 1;
}
}
if (port_separator_pos != base::StringPiece::npos &&
!SetPort(host_and_port.substr(port_separator_pos + 1))) {
return PARSE_ERROR_INVALID_PORT;
}
// Note: this substr() will be the entire string if the port position wasn't
// found.
host_piece = host_and_port.substr(0, port_pos);
// Note: this substr() will be the entire string if the port position
// wasn't found.
base::StringPiece host_piece = host_and_port.substr(0, port_separator_pos);
// The first component can optionally be '*' to match all subdomains.
std::vector<base::StringPiece> host_components = base::SplitStringPiece(
......
......@@ -20,7 +20,8 @@ class GURL;
// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
// <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' |
// 'chrome-extension' | 'filesystem'
// <host> := '*' | '*.' <anychar except '/' and '*'>+
// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
// '*.' <anychar except '/' and '*'>+
// <port> := [':' ('*' | <port number between 0 and 65535>)]
// <path> := '/' <any chars>
//
......@@ -36,6 +37,7 @@ class GURL;
// - https://*.google.com/foo*bar
// - file://monkey*
// - http://127.0.0.1/*
// - http://[2607:f8b0:4005:805::200e]/*
//
// Examples of invalid patterns:
// - http://* -- path not specified
......
......@@ -458,6 +458,19 @@ TEST(URLPatternSetTest, AddOrigin) {
URLPattern::SCHEME_HTTP, GURL("https://google.com/")));
}
TEST(URLPatternSet, AddOriginIPv6) {
{
URLPatternSet set;
EXPECT_TRUE(set.AddOrigin(URLPattern::SCHEME_HTTP,
GURL("http://[2607:f8b0:4005:805::200e]/*")));
}
{
URLPatternSet set;
EXPECT_TRUE(set.AddOrigin(URLPattern::SCHEME_HTTP,
GURL("http://[2607:f8b0:4005:805::200e]/")));
}
}
TEST(URLPatternSetTest, ToStringVector) {
URLPatternSet set;
AddPattern(&set, "https://google.com/");
......
......@@ -101,6 +101,62 @@ TEST(ExtensionURLPatternTest, Ports) {
}
}
TEST(ExtensionURLPatternTest, IPv6Patterns) {
constexpr struct {
const char* pattern;
const char* expected_host;
const char* expected_port;
} kSuccessTestPatterns[] = {
{"http://[2607:f8b0:4005:805::200e]/", "[2607:f8b0:4005:805::200e]", "*"},
{"http://[2607:f8b0:4005:805::200e]/*", "[2607:f8b0:4005:805::200e]",
"*"},
{"http://[2607:f8b0:4005:805::200e]:8888/*", "[2607:f8b0:4005:805::200e]",
"8888"},
};
for (const auto& test_case : kSuccessTestPatterns) {
SCOPED_TRACE(test_case.pattern);
URLPattern pattern(URLPattern::SCHEME_HTTP);
EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse(test_case.pattern));
EXPECT_EQ(test_case.expected_host, pattern.host());
EXPECT_EQ(test_case.expected_port, pattern.port());
}
constexpr struct {
const char* pattern;
URLPattern::ParseResult expected_failure;
} kFailureTestPatterns[] = {
// No port specified, but port separator.
{"http://[2607:f8b0:4005:805::200e]:/*",
URLPattern::PARSE_ERROR_INVALID_PORT},
// No host.
{"http://[]:8888/*", URLPattern::PARSE_ERROR_EMPTY_HOST},
// No closing bracket (`]`).
{"http://[2607:f8b0:4005:805::200e/*",
URLPattern::PARSE_ERROR_INVALID_HOST},
// Two closing brackets (`]]`).
{"http://[2607:f8b0:4005:805::200e]]/*",
URLPattern::PARSE_ERROR_INVALID_HOST},
// Two open brackets (`[[`).
{"http://[[2607:f8b0:4005:805::200e]/*",
URLPattern::PARSE_ERROR_INVALID_HOST},
// Too few colons in the last chunk.
{"http://[2607:f8b0:4005:805:200e]/*",
URLPattern::PARSE_ERROR_INVALID_HOST},
// Non-hex piece.
{"http://[2607:f8b0:4005:805:200e:12:bogus]/*",
URLPattern::PARSE_ERROR_INVALID_HOST},
{"http://[[2607:f8b0:4005:805::200e]:abc/*",
URLPattern::PARSE_ERROR_INVALID_PORT},
};
for (const auto& test_case : kFailureTestPatterns) {
SCOPED_TRACE(test_case.pattern);
URLPattern pattern(URLPattern::SCHEME_HTTP);
EXPECT_EQ(test_case.expected_failure, pattern.Parse(test_case.pattern));
}
}
// all pages for a given scheme
TEST(ExtensionURLPatternTest, Match1) {
URLPattern pattern(kAllSchemes);
......
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