| // Copyright 2024 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "components/url_pattern/simple_url_pattern_matcher.h" | |
| #include <algorithm> | |
| #include <memory> | |
| #include <optional> | |
| #include <string_view> | |
| #include "base/logging.h" | |
| #include "base/strings/strcat.h" | |
| #include "base/strings/string_number_conversions.h" | |
| #include "base/strings/string_util.h" | |
| #include "base/types/expected.h" | |
| #include "components/url_pattern/url_pattern_util.h" | |
| #include "third_party/abseil-cpp/absl/status/status.h" | |
| #include "third_party/liburlpattern/constructor_string_parser.h" | |
| #include "third_party/liburlpattern/parse.h" | |
| #include "third_party/liburlpattern/pattern.h" | |
| #include "third_party/liburlpattern/utils.h" | |
| #include "third_party/re2/src/re2/re2.h" | |
| #include "url/gurl.h" | |
| #include "url/url_util.h" | |
| namespace url_pattern { | |
| namespace { | |
| // https://urlpattern.spec.whatwg.org/#default-options | |
| constexpr liburlpattern::Options kDefaultOptions = {.delimiter_list = "", | |
| .prefix_list = "", | |
| .sensitive = true, | |
| .strict = true}; | |
| // https://urlpattern.spec.whatwg.org/#hostname-options | |
| constexpr liburlpattern::Options kHostnameOptions = {.delimiter_list = ".", | |
| .prefix_list = "", | |
| .sensitive = true, | |
| .strict = true}; | |
| // https://urlpattern.spec.whatwg.org/#pathname-options | |
| constexpr liburlpattern::Options kPathnameOptions = {.delimiter_list = "/", | |
| .prefix_list = "/", | |
| .sensitive = true, | |
| .strict = true}; | |
| std::string EscapePatternString(std::string_view input) { | |
| std::string result; | |
| result.reserve(input.length()); | |
| liburlpattern::EscapePatternStringAndAppend(input, result); | |
| return result; | |
| } | |
| // Utility function to determine if a pathname is absolute or not. We do some | |
| // additional checking for escaped or grouped slashes. | |
| // | |
| // Note: This is partially copied from | |
| // third_party/blink/renderer/core/url_pattern/url_pattern.cc | |
| bool IsAbsolutePathname(std::string_view pathname) { | |
| if (pathname.empty()) { | |
| return false; | |
| } | |
| if (pathname[0] == '/') { | |
| return true; | |
| } | |
| if (pathname.length() < 2) { | |
| return false; | |
| } | |
| // Patterns treat escaped slashes and slashes within an explicit grouping as | |
| // valid leading slashes. For example, "\/foo" or "{/foo}". Patterns do | |
| // not consider slashes within a custom regexp group as valid for the leading | |
| // pathname slash for now. To support that we would need to be able to | |
| // detect things like ":name_123(/foo)" as a valid leading group in a pattern, | |
| // but that is considered too complex for now. | |
| if ((pathname[0] == '\\' || pathname[0] == '{') && pathname[1] == '/') { | |
| return true; | |
| } | |
| return false; | |
| } | |
| std::string ResolveRelativePathnamePattern(const GURL* base_url, | |
| std::string_view pathname) { | |
| if (base_url && base_url->IsStandard() && !IsAbsolutePathname(pathname)) { | |
| std::string base_path = EscapePatternString(base_url->path()); | |
| auto slash_index = base_path.rfind('/'); | |
| if (slash_index != std::string::npos) { | |
| // Extract the baseURL path up to and including the first slash. Append | |
| // the relative init pathname to it. | |
| base_path.resize(slash_index + 1); | |
| base_path += pathname; | |
| return base_path; | |
| } | |
| } | |
| return std::string(pathname); | |
| } | |
| } // namespace | |
| SimpleUrlPatternMatcher::PatternInit::PatternInit( | |
| std::optional<std::string> protocol, | |
| std::optional<std::string> username, | |
| std::optional<std::string> password, | |
| std::optional<std::string> hostname, | |
| std::optional<std::string> port, | |
| std::optional<std::string> pathname, | |
| std::optional<std::string> search, | |
| std::optional<std::string> hash) | |
| : protocol_(std::move(protocol)), | |
| username_(std::move(username)), | |
| password_(std::move(password)), | |
| hostname_(std::move(hostname)), | |
| port_(std::move(port)), | |
| pathname_(std::move(pathname)), | |
| search_(std::move(search)), | |
| hash_(std::move(hash)) {} | |
| SimpleUrlPatternMatcher::PatternInit::~PatternInit() = default; | |
| SimpleUrlPatternMatcher::PatternInit::PatternInit(PatternInit&&) = default; | |
| SimpleUrlPatternMatcher::PatternInit& | |
| SimpleUrlPatternMatcher::PatternInit::operator=(PatternInit&&) = default; | |
| // static | |
| base::expected<SimpleUrlPatternMatcher::Component, std::string> | |
| SimpleUrlPatternMatcher::Component::Create( | |
| std::optional<std::string_view> pattern, | |
| liburlpattern::EncodeCallback encode_callback, | |
| const liburlpattern::Options& options) { | |
| base::expected<liburlpattern::Pattern, absl::Status> parse_result = | |
| liburlpattern::Parse(pattern.value_or("*"), encode_callback, options); | |
| if (!parse_result.has_value()) { | |
| return base::unexpected("Failed to parse pattern"); | |
| } | |
| if (parse_result->HasRegexGroups()) { | |
| return base::unexpected("Regexp groups are not supported"); | |
| } | |
| std::unique_ptr<re2::RE2> regex; | |
| if (!parse_result->CanDirectMatch()) { | |
| std::string regex_string = parse_result->GenerateRegexString(); | |
| if (options.delimiter_list.empty()) { | |
| // When `delimiter_list` is empty, `liburlpattern` generates the | |
| // ECMAScript segment wildcard regexp `[^]+?`, which is invalid in RE2 | |
| // (where `[^]` treats `]` as a literal character inside an unclosed | |
| // character class). Since custom regexp groups are rejected above and | |
| // fixed text is escaped, `[^]+?` can only originate from a segment | |
| // wildcard part. Replace it with `.+?` for RE2 compatibility (matching | |
| // `kFullWildcardRegex` which uses `.*`). | |
| base::ReplaceSubstringsAfterOffset(®ex_string, 0, "[^]+?", ".+?"); | |
| } | |
| regex = std::make_unique<RE2>(regex_string); | |
| if (!regex->ok()) { | |
| return base::unexpected( | |
| base::StrCat({"Failed to compile pattern ", regex_string})); | |
| } | |
| } | |
| return Component(std::move(parse_result.value()), std::move(regex), | |
| base::PassKey<Component>()); | |
| } | |
| SimpleUrlPatternMatcher::Component::Component(liburlpattern::Pattern pattern, | |
| std::unique_ptr<re2::RE2> regex, | |
| base::PassKey<Component>) | |
| : pattern_(std::move(pattern)), regex_(std::move(regex)) {} | |
| SimpleUrlPatternMatcher::Component::Component(Component&&) = default; | |
| SimpleUrlPatternMatcher::Component& | |
| SimpleUrlPatternMatcher::Component::operator=(Component&&) = default; | |
| SimpleUrlPatternMatcher::Component::~Component() = default; | |
| bool SimpleUrlPatternMatcher::Component::Match(std::string_view value) const { | |
| if (pattern_.CanDirectMatch()) { | |
| return pattern_.DirectMatch(value, nullptr); | |
| } | |
| CHECK(regex_); | |
| return RE2::FullMatch(value, *regex_); | |
| } | |
| // static | |
| base::expected<std::unique_ptr<SimpleUrlPatternMatcher>, std::string> | |
| SimpleUrlPatternMatcher::Create(std::string_view constructor_string, | |
| const GURL* base_url) { | |
| std::optional<Component> protocol_component; | |
| bool protocol_matches_a_special_scheme_flag = false; | |
| auto pattern_result = | |
| CreatePatternInit(constructor_string, base_url, &protocol_component, | |
| &protocol_matches_a_special_scheme_flag); | |
| if (!pattern_result.has_value()) { | |
| return base::unexpected(pattern_result.error()); | |
| } | |
| return CreateFromPatternInit(pattern_result.value(), | |
| std::move(protocol_component), | |
| protocol_matches_a_special_scheme_flag); | |
| } | |
| static base::expected<liburlpattern::ConstructorStringParser, std::string> | |
| ParseConstructorString( | |
| std::string_view constructor_string, | |
| std::optional<SimpleUrlPatternMatcher::Component>* protocol_component_out, | |
| bool* protocol_matches_a_special_scheme_flag_out) { | |
| // Spec: Set init to the result of running parse a constructor string given | |
| // input. | |
| // https://urlpattern.spec.whatwg.org/#parse-a-constructor-string | |
| liburlpattern::ConstructorStringParser constructor_string_parser( | |
| constructor_string); | |
| std::optional<SimpleUrlPatternMatcher::Component> protocol_component; | |
| bool protocol_matches_a_special_scheme_flag = false; | |
| absl::Status result = constructor_string_parser.Parse( | |
| [&protocol_component, &protocol_matches_a_special_scheme_flag]( | |
| std::string_view protocol_string) | |
| -> base::expected<bool, absl::Status> { | |
| // Spec: Let protocol component be the result of compiling a component | |
| // given protocol string, canonicalize a protocol, and default options. | |
| auto component_result = SimpleUrlPatternMatcher::Component::Create( | |
| protocol_string, url_pattern::ProtocolEncodeCallback, | |
| kDefaultOptions); | |
| if (!component_result.has_value()) { | |
| return base::unexpected(absl::InvalidArgumentError( | |
| base::StrCat({component_result.error(), " for protocol"}))); | |
| } | |
| protocol_component = std::move(component_result.value()); | |
| // Spec: If the result of running protocol component matches a special | |
| // scheme given protocol component is true, then set parser’s protocol | |
| // matches a special scheme flag to true. | |
| protocol_matches_a_special_scheme_flag = std::ranges::any_of( | |
| url::GetStandardSchemes(), | |
| [&protocol_component](const std::string& scheme) { | |
| return protocol_component->Match(scheme); | |
| }); | |
| return protocol_matches_a_special_scheme_flag; | |
| }); | |
| if (!result.ok()) { | |
| return base::unexpected(std::string(result.message())); | |
| } | |
| // `protocol_matcher_out` can be nullptr in tests. | |
| if (protocol_component_out && protocol_component) { | |
| *protocol_component_out = std::move(*protocol_component); | |
| } | |
| // `protocol_matches_a_special_scheme_flag_out` can be nullptr in tests. | |
| if (protocol_matches_a_special_scheme_flag_out) { | |
| *protocol_matches_a_special_scheme_flag_out = | |
| protocol_matches_a_special_scheme_flag; | |
| } | |
| return std::move(constructor_string_parser); | |
| } | |
| // static | |
| base::expected<SimpleUrlPatternMatcher::PatternInit, std::string> | |
| SimpleUrlPatternMatcher::CreatePatternInit( | |
| std::string_view constructor_string, | |
| const GURL* base_url, | |
| std::optional<Component>* protocol_component_out, | |
| bool* protocol_matches_a_special_scheme_flag_out) { | |
| if (base_url && !base_url->is_valid()) { | |
| return base::unexpected("Invalid base URL"); | |
| } | |
| auto constructor_string_parser = | |
| ParseConstructorString(constructor_string, protocol_component_out, | |
| protocol_matches_a_special_scheme_flag_out); | |
| if (!constructor_string_parser.has_value()) { | |
| return base::unexpected(constructor_string_parser.error()); | |
| } | |
| const liburlpattern::ConstructorStringParser::Result& init = | |
| constructor_string_parser->GetResult(); | |
| // Spec: Let processedInit be the result of process a URLPatternInit given | |
| // init, "pattern", null, null, null, null, null, null, null, and null. | |
| // | |
| // The following code are running shortcuts of the steps of "process a | |
| // URLPatternInit". | |
| // https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit | |
| // If base_url is required to complete the URLPatternInit according to the | |
| // spec but is not given, an error is returned. | |
| // | |
| // [protocol] | |
| // - Spec: If init["protocol"] does not exist, then set result["protocol"] to | |
| // the result of processing a base URL string given baseURL’s scheme and | |
| // type. | |
| // Note: "process a base URL string" returns the result of "escaping a pattern | |
| // string" when |type| is "pattern". | |
| // - Spec: If init["protocol"] exists, then set result["protocol"] to the | |
| // result of process protocol for init given init["protocol"] and type. | |
| // Note: "process protocol for init" removes a single trailing ":". But | |
| // ConstructorStringParser doesn't set the trailing ":". So we don't | |
| // need the logic for the trailing ":" removal. | |
| if (!init.protocol && !base_url) { | |
| return base::unexpected("Protocol may not be omitted"); | |
| } | |
| std::optional<std::string> protocol = | |
| init.protocol ? std::string(*init.protocol) | |
| : EscapePatternString(base_url->scheme()); | |
| // [username] | |
| // - Spec: If type is not "pattern" and init contains none of "protocol", | |
| // "hostname", "port" and "username", then set result["username"] to the | |
| // result of processing a base URL string given baseURL’s username and type. | |
| // Note: We do nothing here because type is "pattern". | |
| // - Spec: If init["username"] exists, then set result["username"] to the | |
| // result of process username for init given init["username"] and type. | |
| // Note: "process username for init" do nothing when type is "pattern". | |
| std::optional<std::string> username = | |
| init.username ? std::make_optional(std::string(*init.username)) | |
| : std::nullopt; | |
| // [password] | |
| // - Spec: If type is not "pattern" and init contains none of "protocol", | |
| // "hostname", "port", "username" and "password", then set | |
| // result["password"] to the result of processing a base URL string given | |
| // baseURL’s password and type. | |
| // Note: We do nothing here because type is "pattern". | |
| // - Spec: If init["password"] exists, then set result["password"] to the | |
| // result of process password for init given init["password"] and type. | |
| // Note: "process password for init" do nothing when type is "pattern". | |
| std::optional<std::string> password = | |
| init.password ? std::make_optional(std::string(*init.password)) | |
| : std::nullopt; | |
| // [hostname] | |
| // - Spec: If init contains neither "protocol" nor "hostname", then: | |
| // - Let baseHost be baseURL’s host. | |
| // - If baseHost is null, then set baseHost to the empty string. | |
| // - Set result["hostname"] to the result of processing a base URL string | |
| // given baseHost and type. | |
| // - Spec: If init["hostname"] exists, then set result["hostname"] to the | |
| // result of process hostname for init given init["hostname"] and type. | |
| // Note: "process hostname for init" do nothing when type is "pattern". | |
| std::optional<std::string> hostname = | |
| init.hostname | |
| ? std::make_optional(std::string(*init.hostname)) | |
| : (init.protocol || !base_url | |
| ? std::nullopt | |
| : std::make_optional(EscapePatternString(base_url->host()))); | |
| // [port] | |
| // - Spec: If init contains none of "protocol", "hostname", and "port", then: | |
| // - If baseURL’s port is null, then set result["port"] to the empty string. | |
| // - Otherwise, set result["port"] to baseURL’s port, serialized. | |
| // - Spec: If init["port"] exists, then set result["port"] to the result of | |
| // process port for init given init["port"], result["protocol"], and type. | |
| // Note: "process port for init" do nothing when type is "pattern". | |
| std::optional<std::string> port = | |
| init.port ? std::make_optional(std::string(*init.port)) | |
| : ((init.protocol || init.hostname || !base_url) | |
| ? std::nullopt | |
| : std::make_optional(base_url->GetPort())); | |
| // [pathname] | |
| // - Spec: If init contains none of "protocol", "hostname", "port", and | |
| // "pathname", then set result["pathname"] to the result of processing a | |
| // base URL string given the result of URL path serializing baseURL and | |
| // type. | |
| // - Spec: If init["pathname"] exists: | |
| // - Set result["pathname"] to init["pathname"]. | |
| // - If the following are all true: | |
| // * baseURL is not null; | |
| // * baseURL has an opaque path; and | |
| // * the result of running is an absolute pathname given | |
| // result["pathname"] and type is false, | |
| // then: | |
| // - Let baseURLPath be the result of running process a base URL string | |
| // given the result of URL path serializing baseURL and type. | |
| // - Let slash index be the index of the last U+002F (/) code point found | |
| // in baseURLPath, interpreted as a sequence of code points, or null if | |
| // there are no instances of the code point. | |
| // - If slash index is not null: | |
| // - Let new pathname be the code point substring from 0 to slash index + | |
| // 1 within baseURLPath. | |
| // - Append result["pathname"] to the end of new pathname. | |
| // - Set result["pathname"] to new pathname. | |
| // - Set result["pathname"] to the result of process pathname for init given | |
| // result["pathname"], result["protocol"], and type. | |
| // Note: The second logic is implemented in ResolveRelativePathnamePattern(). | |
| // "process pathname for init" do nothing when type is "pattern". | |
| if (!base_url && init.pathname && url::IsStandard(*protocol) && | |
| !IsAbsolutePathname(*init.pathname)) { | |
| return base::unexpected("Relative pathname not allowed"); | |
| } | |
| std::optional<std::string> pathname = | |
| init.pathname | |
| ? std::make_optional( | |
| ResolveRelativePathnamePattern(base_url, *init.pathname)) | |
| : ((init.protocol || init.hostname || init.port || !base_url) | |
| ? std::nullopt | |
| : std::make_optional(EscapePatternString(base_url->path()))); | |
| // [search] | |
| // - Spec: If init contains none of "protocol", "hostname", "port", | |
| // "pathname", and "search", then: | |
| // - Let baseQuery be baseURL’s query. | |
| // - If baseQuery is null, then set baseQuery to the empty string. | |
| // - Set result["search"] to the result of processing a base URL string | |
| // given baseQuery and type. | |
| // - Spec: If init["search"] exists then set result["search"] to the result of | |
| // process search for init given init["search"] and type. | |
| // Note: "process search for init" removes a single leading "?". But | |
| // ConstructorStringParser doesn't set the leading "?". So we don't | |
| // need the logic for the leading "?" removal. | |
| std::optional<std::string> search = | |
| init.search | |
| ? std::make_optional(std::string(*init.search)) | |
| : ((init.protocol || init.hostname || init.port || init.pathname || | |
| !base_url) | |
| ? std::nullopt | |
| : std::make_optional(EscapePatternString(base_url->query()))); | |
| // [hash] | |
| // - Spec: If init contains none of "protocol", "hostname", "port", | |
| // "pathname", "search", and "hash", then: | |
| // - Let baseFragment be baseURL’s fragment. | |
| // - If baseFragment is null, then set baseFragment to the empty string. | |
| // - Set result["hash"] to the result of processing a base URL string given | |
| // baseFragment and type. | |
| // - Spec: If init["hash"] exists then set result["hash"] to the result of | |
| // process hash for init given init["hash"] and type. | |
| // Note: "process hash for init" removes a single leading "#". But | |
| // ConstructorStringParser doesn't set the leading "#". So we don't | |
| // need the logic for the leading "#" removal. | |
| std::optional<std::string> hash = | |
| init.hash | |
| ? std::make_optional(std::string(*init.hash)) | |
| : ((init.protocol || init.hostname || init.port || init.pathname || | |
| init.search || !base_url) | |
| ? std::nullopt | |
| : std::make_optional(EscapePatternString(base_url->ref()))); | |
| CHECK(protocol); | |
| // Treat default port as an empty string pattern. This logic is in the | |
| // "initialize a URLPattern" step. | |
| // https://urlpattern.spec.whatwg.org/#urlpattern-initialize | |
| // - Spec: If processedInit["protocol"] is a special scheme and | |
| // processedInit["port"] is its corresponding default port, then set | |
| // processedInit["port"] to the empty string. | |
| if (port) { | |
| int default_port = url::DefaultPortForScheme(*protocol); | |
| if (default_port != url::PORT_UNSPECIFIED && | |
| base::NumberToString(default_port) == *port) { | |
| port = ""; | |
| } | |
| } | |
| return PatternInit(std::move(protocol), std::move(username), | |
| std::move(password), std::move(hostname), std::move(port), | |
| std::move(pathname), std::move(search), std::move(hash)); | |
| } | |
| // static | |
| base::expected<std::unique_ptr<SimpleUrlPatternMatcher>, std::string> | |
| SimpleUrlPatternMatcher::CreateFromPatternInit( | |
| const PatternInit& pattern, | |
| std::optional<Component> precomputed_protocol_component, | |
| bool protocol_matches_a_special_scheme_flag) { | |
| // We run the steps of compiling components in the "initialize a URLPattern" | |
| // step. | |
| // https://urlpattern.spec.whatwg.org/#urlpattern-initialize | |
| // We always provide `base_url` for creating a `SimpleUrlPatternMatcher`. So | |
| // `pattern.protocol()` must be set. | |
| CHECK(pattern.protocol()); | |
| std::optional<Component> protocol_component = | |
| std::move(precomputed_protocol_component); | |
| if (!protocol_component) { | |
| // Spec: Set this’s protocol component to the result of compiling a | |
| // component given processedInit["protocol"], canonicalize a protocol, | |
| // and default options. | |
| auto protocol_component_result = | |
| Component::Create(*pattern.protocol(), | |
| url_pattern::ProtocolEncodeCallback, kDefaultOptions); | |
| if (!protocol_component_result.has_value()) { | |
| return base::unexpected( | |
| base::StrCat({protocol_component_result.error(), " for protocol"})); | |
| } | |
| protocol_component = std::move(protocol_component_result.value()); | |
| protocol_matches_a_special_scheme_flag = | |
| std::ranges::any_of(url::GetStandardSchemes(), | |
| [&protocol_component](const std::string& scheme) { | |
| return protocol_component->Match(scheme); | |
| }); | |
| } | |
| #define MAYBE_COMPILE_PATTERN(type, callback, options) \ | |
| std::optional<Component> type##_component; \ | |
| auto type##_result = Component::Create(pattern.type(), callback, options); \ | |
| if (!type##_result.has_value()) { \ | |
| return base::unexpected( \ | |
| base::StrCat({type##_result.error(), " for " #type})); \ | |
| } \ | |
| type##_component = std::move(type##_result.value()); | |
| // Spec: Set this’s username component to the result of compiling a component | |
| // given processedInit["username"], canonicalize a username, and default | |
| // options. | |
| MAYBE_COMPILE_PATTERN(username, url_pattern::UsernameEncodeCallback, | |
| kDefaultOptions); | |
| // Spec: Set this’s password component to the result of compiling a component | |
| // given processedInit["password"], canonicalize a password, and default | |
| // options. | |
| MAYBE_COMPILE_PATTERN(password, url_pattern::PasswordEncodeCallback, | |
| kDefaultOptions); | |
| // Spec: | |
| // - If the result running hostname pattern is an IPv6 address given | |
| // processedInit["hostname"] is true, then set this’s hostname component to | |
| // the result of compiling a component given processedInit["hostname"], | |
| // canonicalize an IPv6 hostname, and hostname options. | |
| // - Otherwise, set this’s hostname component to the result of compiling a | |
| // component given processedInit["hostname"], canonicalize a hostname, and | |
| // hostname options. | |
| MAYBE_COMPILE_PATTERN(hostname, | |
| url_pattern::TreatAsIPv6Hostname(*pattern.hostname()) | |
| ? url_pattern::IPv6HostnameEncodeCallback | |
| : url_pattern::HostnameEncodeCallback, | |
| kHostnameOptions); | |
| // Spec: Set this’s port component to the result of compiling a component | |
| // given processedInit["port"], canonicalize a port, and default options. | |
| MAYBE_COMPILE_PATTERN(port, url_pattern::PortEncodeCallback, kDefaultOptions); | |
| // Spec: | |
| // - Let compileOptions be a copy of the default options with the ignore case | |
| // property set to options["ignoreCase"]. | |
| // - If the result of running protocol component matches a special scheme | |
| // given this’s protocol component is true, then: | |
| // - Let pathCompileOptions be copy of the pathname options with the ignore | |
| // case property set to options["ignoreCase"]. | |
| // - Set this’s pathname component to the result of compiling a component | |
| // given processedInit["pathname"], canonicalize a pathname, and | |
| // pathCompileOptions. | |
| // - Otherwise set this’s pathname component to the result of compiling a | |
| // component given processedInit["pathname"], canonicalize an opaque | |
| // pathname, and compileOptions. | |
| // Note: We use the default false for options["ignoreCase"]. | |
| MAYBE_COMPILE_PATTERN(pathname, | |
| protocol_matches_a_special_scheme_flag | |
| ? url_pattern::StandardURLPathnameEncodeCallback | |
| : url_pattern::PathURLPathnameEncodeCallback, | |
| protocol_matches_a_special_scheme_flag | |
| ? kPathnameOptions | |
| : kDefaultOptions); | |
| // Spec: Set this’s search component to the result of compiling a component | |
| // given processedInit["search"], canonicalize a search, and compileOptions. | |
| MAYBE_COMPILE_PATTERN(search, url_pattern::SearchEncodeCallback, | |
| kDefaultOptions); | |
| // Spec: Set this’s hash component to the result of compiling a component | |
| // given processedInit["hash"], canonicalize a hash, and compileOptions. | |
| MAYBE_COMPILE_PATTERN(hash, url_pattern::HashEncodeCallback, kDefaultOptions); | |
| #undef MAYBE_COMPILE_PATTERN | |
| return std::make_unique<SimpleUrlPatternMatcher>( | |
| std::move(*protocol_component), std::move(*username_component), | |
| std::move(*password_component), std::move(*hostname_component), | |
| std::move(*port_component), std::move(*pathname_component), | |
| std::move(*search_component), std::move(*hash_component), | |
| base::PassKey<SimpleUrlPatternMatcher>()); | |
| } | |
| SimpleUrlPatternMatcher::SimpleUrlPatternMatcher( | |
| Component protocol, | |
| Component username, | |
| Component password, | |
| Component hostname, | |
| Component port, | |
| Component pathname, | |
| Component search, | |
| Component hash, | |
| base::PassKey<SimpleUrlPatternMatcher>) | |
| : protocol_(std::move(protocol)), | |
| username_(std::move(username)), | |
| password_(std::move(password)), | |
| hostname_(std::move(hostname)), | |
| port_(std::move(port)), | |
| pathname_(std::move(pathname)), | |
| search_(std::move(search)), | |
| hash_(std::move(hash)) {} | |
| bool SimpleUrlPatternMatcher::Match(const GURL& url) const { | |
| return protocol_.Match(url.scheme()) && username_.Match(url.username()) && | |
| password_.Match(url.password()) && hostname_.Match(url.host()) && | |
| port_.Match(url.port()) && pathname_.Match(url.path()) && | |
| search_.Match(url.query()) && hash_.Match(url.ref()); | |
| } | |
| bool SimpleUrlPatternMatcher::HostOnlyMatch(const GURL& url) const { | |
| return hostname_.Match(url.host()); | |
| } | |
| SimpleUrlPatternMatcher::~SimpleUrlPatternMatcher() = default; | |
| } // namespace url_pattern |