| // 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. | |
| #ifndef COMPONENTS_URL_PATTERN_SIMPLE_URL_PATTERN_MATCHER_H_ | |
| #define COMPONENTS_URL_PATTERN_SIMPLE_URL_PATTERN_MATCHER_H_ | |
| #include <memory> | |
| #include <string> | |
| #include <string_view> | |
| #include "base/component_export.h" | |
| #include "base/types/expected.h" | |
| #include "base/types/pass_key.h" | |
| #include "third_party/liburlpattern/parse.h" | |
| #include "third_party/liburlpattern/pattern.h" | |
| class GURL; | |
| namespace re2 { | |
| class RE2; | |
| } | |
| namespace url_pattern { | |
| // This class partially implements URL Pattern spec which is needed for | |
| // Dictionary URL matching of Compression Dictionary Transport. | |
| // https://urlpattern.spec.whatwg.org/ | |
| // https://www.ietf.org/archive/id/draft-ietf-httpbis-compression-dictionary-01.html#name-dictionary-url-matching | |
| // It's also used in blink's inspector. The inspector uses it with string inputs | |
| // instead of JS objects, which makes blink::SafeUrlPattern impractical. | |
| // | |
| // This class can be created from a constructor string and a base URL | |
| // and can run the `test` method of URLPattern only with a URL. | |
| // | |
| // This class doesn't support regexp groups, because this class is used in the | |
| // network service, and there is a security concern in allowing user-defined | |
| // regular expressions. Also this class doesn't support setting `ignoreCase` | |
| // option to true. | |
| // | |
| // Note: We share the limitation of regexp groups with ServiceWorker static | |
| // routing API. For that API, we accept URLPattern JS objects without regexp | |
| // groups, and contvet them to blink::SafeUrlPattern structures in Blink, and | |
| // pass them to the browser process via IPC, and evaluate the pattern with | |
| // resource URLs. For Compression Dictionary Transport feature, we parses the | |
| // constructor string and evaluate the pattern with resource URLs in the network | |
| // service. To simplify this class, this class doesn't share any logic with | |
| // ServiceWorker static routing API. But if we will have more usecases of | |
| // URLPattern, we may need to consider combining those logics. | |
| // Context: https://crrev.com/c/5209732/comment/2d53e11c_e4b8c868/ | |
| class SimpleUrlPatternMatcher { | |
| public: | |
| // This class partially represents `URLPatternInit` in the URL Pattern spec. | |
| // https://urlpattern.spec.whatwg.org/#dictdef-urlpatterninit | |
| // The only difference is that this class doesn't have a `baseURL` field. | |
| class PatternInit { | |
| public: | |
| 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); | |
| ~PatternInit(); | |
| PatternInit(const PatternInit&) = delete; | |
| PatternInit& operator=(const PatternInit&) = delete; | |
| PatternInit(PatternInit&&); | |
| PatternInit& operator=(PatternInit&&); | |
| bool operator==(const PatternInit& other) const = default; | |
| const std::optional<std::string>& protocol() const { return protocol_; } | |
| const std::optional<std::string>& username() const { return username_; } | |
| const std::optional<std::string>& password() const { return password_; } | |
| const std::optional<std::string>& hostname() const { return hostname_; } | |
| const std::optional<std::string>& port() const { return port_; } | |
| const std::optional<std::string>& pathname() const { return pathname_; } | |
| const std::optional<std::string>& search() const { return search_; } | |
| const std::optional<std::string>& hash() const { return hash_; } | |
| private: | |
| 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_; | |
| }; | |
| // This class represents `component` struct in the URL Pattern spec. | |
| // https://urlpattern.spec.whatwg.org/#component | |
| class Component { | |
| public: | |
| // Compile a component from a pattern. | |
| // https://urlpattern.spec.whatwg.org/#compile-a-component | |
| static base::expected<Component, std::string> Create( | |
| std::optional<std::string_view> pattern, | |
| liburlpattern::EncodeCallback encode_callback, | |
| const liburlpattern::Options& options); | |
| Component(liburlpattern::Pattern pattern, | |
| std::unique_ptr<re2::RE2> regex, | |
| base::PassKey<Component>); | |
| ~Component(); | |
| Component(const Component&) = delete; | |
| Component& operator=(const Component&) = delete; | |
| Component(Component&&); | |
| Component& operator=(Component&&); | |
| // This method partially implements `match` method of URLPattern in the | |
| // URL Pattern spec. | |
| // https://urlpattern.spec.whatwg.org/#urlpattern-match | |
| bool Match(std::string_view value) const; | |
| private: | |
| liburlpattern::Pattern pattern_; | |
| // This is null if `pattern_` supports direct matching. | |
| std::unique_ptr<re2::RE2> regex_; | |
| }; | |
| // Creates a SimpleUrlPatternMatcher from a constructor string and a base URL. | |
| // If the constructor string is invalid or it contains regexp group, this | |
| // method returns an error string. If `base_url` is nullptr, relative patterns | |
| // in `constructor_string` produce an error. | |
| static base::expected<std::unique_ptr<SimpleUrlPatternMatcher>, std::string> | |
| Create(std::string_view constructor_string, const GURL* base_url); | |
| SimpleUrlPatternMatcher(Component protocol, | |
| Component username, | |
| Component password, | |
| Component hostname, | |
| Component port, | |
| Component pathname, | |
| Component search, | |
| Component hash, | |
| base::PassKey<SimpleUrlPatternMatcher>); | |
| SimpleUrlPatternMatcher(const SimpleUrlPatternMatcher&) = delete; | |
| SimpleUrlPatternMatcher& operator=(const SimpleUrlPatternMatcher&) = delete; | |
| ~SimpleUrlPatternMatcher(); | |
| // Performs `test` method of URLPattern with a URL. | |
| // https://urlpattern.spec.whatwg.org/#dom-urlpattern-test | |
| bool Match(const GURL& url) const; | |
| // Convenience method for testing against only the `host` component of the | |
| // pattern. Used by Connection Allowlists | |
| // (https://wicg.github.io/connection-allowlists/) to determine if host | |
| // resolution requests for a given host are allowed. From a spec standpoint, | |
| // this is equivalent to creating a new URLPattern using only the `host` | |
| // component of this pattern, and testing against the new pattern instead. | |
| bool HostOnlyMatch(const GURL& url) const; | |
| private: | |
| friend class SimpleUrlPatternMatcherTest; | |
| // Creates a `PatternInit` with the result of parsing a constructor string and | |
| // apply `base_url` if given. And returns the result of processing a | |
| // URLPatternInit, and processing the default port of the protocol component. | |
| // If `base_url` is nullptr, relative or incomplete PatternInits produce an | |
| // error. | |
| // https://urlpattern.spec.whatwg.org/#parse-a-constructor-string | |
| // https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit | |
| // | |
| // `protocol_component_out` and `protocol_matches_a_special_scheme_flag_out` | |
| // are optional out parameter. When they are set, this method fills them with | |
| // a Component for the protocol component and `protocol matches a special | |
| // scheme flag` in the spec, which are computed while parsing the constructor | |
| // string. | |
| // https://urlpattern.spec.whatwg.org/#compute-protocol-matches-a-special-scheme-flag | |
| static base::expected<PatternInit, std::string> CreatePatternInit( | |
| std::string_view url_pattern, | |
| const GURL* base_url, | |
| std::optional<Component>* protocol_component_out, | |
| bool* protocol_matches_a_special_scheme_flag_out); | |
| // Creates a SimpleUrlPatternMatcher from a `PatternInit` and a precomputed | |
| // protocol component, and a `protocol_matches_a_special_scheme_flag` flag. | |
| static base::expected<std::unique_ptr<SimpleUrlPatternMatcher>, std::string> | |
| CreateFromPatternInit(const PatternInit& pattern, | |
| std::optional<Component> precomputed_protocol_component, | |
| bool protocol_matches_a_special_scheme_flag); | |
| Component protocol_; | |
| Component username_; | |
| Component password_; | |
| Component hostname_; | |
| Component port_; | |
| Component pathname_; | |
| Component search_; | |
| Component hash_; | |
| }; | |
| } // namespace url_pattern | |
| #endif // COMPONENTS_URL_PATTERN_SIMPLE_URL_PATTERN_MATCHER_H_ |