Ada 3.0.1
Fast spec-compliant URL parser
Loading...
Searching...
No Matches
parser-inl.h
Go to the documentation of this file.
1
4#ifndef ADA_PARSER_INL_H
5#define ADA_PARSER_INL_H
6
7#include "ada/expected.h"
8#include "ada/url_pattern.h"
10#include "ada/parser.h"
11
12#include <string_view>
13#include <variant>
14
15namespace ada::parser {
16template <url_pattern_regex::regex_concept regex_provider>
17tl::expected<url_pattern<regex_provider>, errors> parse_url_pattern_impl(
18 std::variant<std::string_view, url_pattern_init> input,
19 const std::string_view* base_url, const url_pattern_options* options) {
20 // Let init be null.
22
23 // If input is a scalar value string then:
24 if (std::holds_alternative<std::string_view>(input)) {
25 // Set init to the result of running parse a constructor string given input.
26 auto parse_result =
28 std::get<std::string_view>(input));
29 if (!parse_result) {
30 ada_log("constructor_string_parser::parse failed");
31 return tl::unexpected(parse_result.error());
32 }
33 init = std::move(*parse_result);
34 // If baseURL is null and init["protocol"] does not exist, then throw a
35 // TypeError.
36 if (!base_url && !init.protocol) {
37 ada_log("base url is null and protocol is not set");
38 return tl::unexpected(errors::type_error);
39 }
40
41 // If baseURL is not null, set init["baseURL"] to baseURL.
42 if (base_url) {
43 init.base_url = std::string(*base_url);
44 }
45 } else {
46 // Assert: input is a URLPatternInit.
47 ADA_ASSERT_TRUE(std::holds_alternative<url_pattern_init>(input));
48 // If baseURL is not null, then throw a TypeError.
49 if (base_url) {
50 ada_log("base url is not null");
51 return tl::unexpected(errors::type_error);
52 }
53 // Optimization: Avoid copy by moving the input value.
54 // Set init to input.
55 init = std::move(std::get<url_pattern_init>(input));
56 }
57
58 // Let processedInit be the result of process a URLPatternInit given init,
59 // "pattern", null, null, null, null, null, null, null, and null.
60 // TODO: Make "pattern" an enum to avoid creating a string everytime.
61 auto processed_init = url_pattern_init::process(init, "pattern");
62 if (!processed_init) {
63 ada_log("url_pattern_init::process failed for init and 'pattern'");
64 return tl::unexpected(processed_init.error());
65 }
66
67 // For each componentName of « "protocol", "username", "password", "hostname",
68 // "port", "pathname", "search", "hash" If processedInit[componentName] does
69 // not exist, then set processedInit[componentName] to "*".
70 ADA_ASSERT_TRUE(processed_init.has_value());
71 if (!processed_init->protocol) processed_init->protocol = "*";
72 if (!processed_init->username) processed_init->username = "*";
73 if (!processed_init->password) processed_init->password = "*";
74 if (!processed_init->hostname) processed_init->hostname = "*";
75 if (!processed_init->port) processed_init->port = "*";
76 if (!processed_init->pathname) processed_init->pathname = "*";
77 if (!processed_init->search) processed_init->search = "*";
78 if (!processed_init->hash) processed_init->hash = "*";
79
80 ada_log("-- processed_init->protocol: ", processed_init->protocol.value());
81 ada_log("-- processed_init->username: ", processed_init->username.value());
82 ada_log("-- processed_init->password: ", processed_init->password.value());
83 ada_log("-- processed_init->hostname: ", processed_init->hostname.value());
84 ada_log("-- processed_init->port: ", processed_init->port.value());
85 ada_log("-- processed_init->pathname: ", processed_init->pathname.value());
86 ada_log("-- processed_init->search: ", processed_init->search.value());
87 ada_log("-- processed_init->hash: ", processed_init->hash.value());
88
89 // If processedInit["protocol"] is a special scheme and processedInit["port"]
90 // is a string which represents its corresponding default port in radix-10
91 // using ASCII digits then set processedInit["port"] to the empty string.
92 // TODO: Optimization opportunity.
93 if (scheme::is_special(*processed_init->protocol)) {
94 std::string_view port = processed_init->port.value();
95 helpers::trim_c0_whitespace(port);
96 if (std::to_string(scheme::get_special_port(*processed_init->protocol)) ==
97 port) {
98 processed_init->port->clear();
99 }
100 }
101
102 // Let urlPattern be a new URL pattern.
103 url_pattern<regex_provider> url_pattern_{};
104
105 // Set urlPattern’s protocol component to the result of compiling a component
106 // given processedInit["protocol"], canonicalize a protocol, and default
107 // options.
108 auto protocol_component = url_pattern_component<regex_provider>::compile(
109 processed_init->protocol.value(),
112 if (!protocol_component) {
113 ada_log("url_pattern_component::compile failed for protocol ",
114 processed_init->protocol.value());
115 return tl::unexpected(protocol_component.error());
116 }
117 url_pattern_.protocol_component = std::move(*protocol_component);
118
119 // Set urlPattern’s username component to the result of compiling a component
120 // given processedInit["username"], canonicalize a username, and default
121 // options.
122 auto username_component = url_pattern_component<regex_provider>::compile(
123 processed_init->username.value(),
126 if (!username_component) {
127 ada_log("url_pattern_component::compile failed for username ",
128 processed_init->username.value());
129 return tl::unexpected(username_component.error());
130 }
131 url_pattern_.username_component = std::move(*username_component);
132
133 // Set urlPattern’s password component to the result of compiling a component
134 // given processedInit["password"], canonicalize a password, and default
135 // options.
136 auto password_component = url_pattern_component<regex_provider>::compile(
137 processed_init->password.value(),
140 if (!password_component) {
141 ada_log("url_pattern_component::compile failed for password ",
142 processed_init->password.value());
143 return tl::unexpected(password_component.error());
144 }
145 url_pattern_.password_component = std::move(*password_component);
146
147 // TODO: Optimization opportunity. The following if statement can be
148 // simplified.
149 // If the result running hostname pattern is an IPv6 address given
150 // processedInit["hostname"] is true, then set urlPattern’s hostname component
151 // to the result of compiling a component given processedInit["hostname"],
152 // canonicalize an IPv6 hostname, and hostname options.
153 if (url_pattern_helpers::is_ipv6_address(processed_init->hostname.value())) {
154 ada_log("processed_init->hostname is ipv6 address");
155 // then set urlPattern’s hostname component to the result of compiling a
156 // component given processedInit["hostname"], canonicalize an IPv6 hostname,
157 // and hostname options.
158 auto hostname_component = url_pattern_component<regex_provider>::compile(
159 processed_init->hostname.value(),
162 if (!hostname_component) {
163 ada_log("url_pattern_component::compile failed for ipv6 hostname ",
164 processed_init->hostname.value());
165 return tl::unexpected(hostname_component.error());
166 }
167 url_pattern_.hostname_component = std::move(*hostname_component);
168 } else {
169 // Otherwise, set urlPattern’s hostname component to the result of compiling
170 // a component given processedInit["hostname"], canonicalize a hostname, and
171 // hostname options.
172 auto hostname_component = url_pattern_component<regex_provider>::compile(
173 processed_init->hostname.value(),
176 if (!hostname_component) {
177 ada_log("url_pattern_component::compile failed for hostname ",
178 processed_init->hostname.value());
179 return tl::unexpected(hostname_component.error());
180 }
181 url_pattern_.hostname_component = std::move(*hostname_component);
182 }
183
184 // Set urlPattern’s port component to the result of compiling a component
185 // given processedInit["port"], canonicalize a port, and default options.
187 processed_init->port.value(), url_pattern_helpers::canonicalize_port,
189 if (!port_component) {
190 ada_log("url_pattern_component::compile failed for port ",
191 processed_init->port.value());
192 return tl::unexpected(port_component.error());
193 }
194 url_pattern_.port_component = std::move(*port_component);
195
196 // Let compileOptions be a copy of the default options with the ignore case
197 // property set to options["ignoreCase"].
199 if (options) {
200 compile_options.ignore_case = options->ignore_case;
201 }
202
203 // TODO: Optimization opportunity: Simplify this if statement.
204 // If the result of running protocol component matches a special scheme given
205 // urlPattern’s protocol component is true, then:
207 regex_provider>(url_pattern_.protocol_component)) {
208 // Let pathCompileOptions be copy of the pathname options with the ignore
209 // case property set to options["ignoreCase"].
210 auto path_compile_options = url_pattern_compile_component_options::PATHNAME;
211 if (options) {
212 path_compile_options.ignore_case = options->ignore_case;
213 }
214
215 // Set urlPattern’s pathname component to the result of compiling a
216 // component given processedInit["pathname"], canonicalize a pathname, and
217 // pathCompileOptions.
218 auto pathname_component = url_pattern_component<regex_provider>::compile(
219 processed_init->pathname.value(),
220 url_pattern_helpers::canonicalize_pathname, path_compile_options);
221 if (!pathname_component) {
222 ada_log("url_pattern_component::compile failed for pathname ",
223 processed_init->pathname.value());
224 return tl::unexpected(pathname_component.error());
225 }
226 url_pattern_.pathname_component = std::move(*pathname_component);
227 } else {
228 // Otherwise set urlPattern’s pathname component to the result of compiling
229 // a component given processedInit["pathname"], canonicalize an opaque
230 // pathname, and compileOptions.
231 auto pathname_component = url_pattern_component<regex_provider>::compile(
232 processed_init->pathname.value(),
234 if (!pathname_component) {
235 ada_log("url_pattern_component::compile failed for opaque pathname ",
236 processed_init->pathname.value());
237 return tl::unexpected(pathname_component.error());
238 }
239 url_pattern_.pathname_component = std::move(*pathname_component);
240 }
241
242 // Set urlPattern’s search component to the result of compiling a component
243 // given processedInit["search"], canonicalize a search, and compileOptions.
245 processed_init->search.value(), url_pattern_helpers::canonicalize_search,
246 compile_options);
247 if (!search_component) {
248 ada_log("url_pattern_component::compile failed for search ",
249 processed_init->search.value());
250 return tl::unexpected(search_component.error());
251 }
252 url_pattern_.search_component = std::move(*search_component);
253
254 // Set urlPattern’s hash component to the result of compiling a component
255 // given processedInit["hash"], canonicalize a hash, and compileOptions.
257 processed_init->hash.value(), url_pattern_helpers::canonicalize_hash,
258 compile_options);
259 if (!hash_component) {
260 ada_log("url_pattern_component::compile failed for hash ",
261 processed_init->hash.value());
262 return tl::unexpected(hash_component.error());
263 }
264 url_pattern_.hash_component = std::move(*hash_component);
265
266 // Return urlPattern.
267 return url_pattern_;
268}
269
270} // namespace ada::parser
271
272#endif // ADA_PARSER_INL_H
static tl::expected< url_pattern_component, errors > compile(std::string_view input, F &encoding_callback, url_pattern_compile_component_options &options)
#define ADA_ASSERT_TRUE(COND)
Includes the definitions for supported parsers.
Definition parser-inl.h:15
tl::expected< url_pattern< regex_provider >, errors > parse_url_pattern_impl(std::variant< std::string_view, url_pattern_init > input, const std::string_view *base_url, const url_pattern_options *options)
Definition parser-inl.h:17
constexpr uint16_t get_special_port(std::string_view scheme) noexcept
Definition scheme-inl.h:57
tl::expected< std::string, errors > canonicalize_opaque_pathname(std::string_view input)
tl::expected< std::string, errors > canonicalize_pathname(std::string_view input)
bool protocol_component_matches_special_scheme(url_pattern_component< regex_provider > &component)
tl::expected< std::string, errors > canonicalize_password(std::string_view input)
tl::expected< std::string, errors > canonicalize_protocol(std::string_view input)
tl::expected< std::string, errors > canonicalize_hostname(std::string_view input)
tl::expected< std::string, errors > canonicalize_hash(std::string_view input)
tl::expected< std::string, errors > canonicalize_port(std::string_view input)
bool is_ipv6_address(std::string_view input) noexcept
tl::expected< std::string, errors > canonicalize_search(std::string_view input)
tl::expected< std::string, errors > canonicalize_ipv6_hostname(std::string_view input)
tl::expected< std::string, errors > canonicalize_username(std::string_view input)
errors
Definition errors.h:10
@ type_error
Definition errors.h:10
Definitions for the parser.
static url_pattern_compile_component_options HOSTNAME
Definition url_pattern.h:99
static url_pattern_compile_component_options PATHNAME
static url_pattern_compile_component_options DEFAULT
Definition url_pattern.h:98
static tl::expected< url_pattern_init, errors > parse(std::string_view input)
std::optional< std::string > protocol
static tl::expected< url_pattern_init, errors > process(url_pattern_init init, std::string_view type, std::optional< std::string_view > protocol=std::nullopt, std::optional< std::string_view > username=std::nullopt, std::optional< std::string_view > password=std::nullopt, std::optional< std::string_view > hostname=std::nullopt, std::optional< std::string_view > port=std::nullopt, std::optional< std::string_view > pathname=std::nullopt, std::optional< std::string_view > search=std::nullopt, std::optional< std::string_view > hash=std::nullopt)
std::optional< std::string > base_url
ada::url_pattern_regex::std_regex_provider regex_provider
Definition url_pattern.cc:9
Declaration for the URLPattern implementation.
Declaration for the URLPattern helpers.