5#ifndef ADA_URL_PATTERN_HELPERS_INL_H
6#define ADA_URL_PATTERN_HELPERS_INL_H
12#include "ada/expected.h"
16#if ADA_INCLUDE_URL_PATTERN
18#if defined(ADA_TESTING) || defined(ADA_LOGGING)
21 case token_type::INVALID_CHAR:
22 return "INVALID_CHAR";
23 case token_type::OPEN:
25 case token_type::CLOSE:
27 case token_type::REGEXP:
29 case token_type::NAME:
31 case token_type::CHAR:
33 case token_type::ESCAPED_CHAR:
34 return "ESCAPED_CHAR";
35 case token_type::OTHER_MODIFIER:
36 return "OTHER_MODIFIER";
37 case token_type::ASTERISK:
47template <url_pattern_regex::regex_concept regex_prov
ider>
48constexpr void constructor_string_parser<regex_provider>::rewind() {
55template <url_pattern_regex::regex_concept regex_prov
ider>
56constexpr bool constructor_string_parser<regex_provider>::is_hash_prefix() {
62template <url_pattern_regex::regex_concept regex_prov
ider>
63constexpr bool constructor_string_parser<regex_provider>::is_search_prefix() {
95template <url_pattern_regex::regex_concept regex_prov
ider>
97constructor_string_parser<regex_provider>::is_non_special_pattern_char(
98 size_t index,
uint32_t value)
const {
106 if (!
token->value.empty() &&
116 return token->type == token_type::CHAR ||
117 token->type == token_type::ESCAPED_CHAR ||
118 token->type == token_type::INVALID_CHAR;
121template <url_pattern_regex::regex_concept regex_prov
ider>
122constexpr const token*
123constructor_string_parser<regex_provider>::get_safe_token(
size_t index)
const {
141template <url_pattern_regex::regex_concept regex_prov
ider>
142constexpr bool constructor_string_parser<regex_provider>::is_group_open()
149template <url_pattern_regex::regex_concept regex_prov
ider>
150constexpr bool constructor_string_parser<regex_provider>::is_group_close()
157template <url_pattern_regex::regex_concept regex_prov
ider>
159constructor_string_parser<regex_provider>::next_is_authority_slashes()
const {
173template <url_pattern_regex::regex_concept regex_prov
ider>
174constexpr bool constructor_string_parser<regex_provider>::is_protocol_suffix()
181template <url_pattern_regex::regex_concept regex_prov
ider>
182void constructor_string_parser<regex_provider>::change_state(
State new_state,
187 if (
state != State::INIT &&
state != State::AUTHORITY &&
188 state != State::DONE) {
192 case State::PROTOCOL: {
196 case State::USERNAME: {
200 case State::PASSWORD: {
204 case State::HOSTNAME: {
212 case State::PATHNAME: {
216 case State::SEARCH: {
235 if ((
state == State::PROTOCOL ||
state == State::AUTHORITY ||
236 state == State::USERNAME ||
state == State::PASSWORD) &&
246 if ((
state == State::PROTOCOL ||
state == State::AUTHORITY ||
247 state == State::USERNAME ||
state == State::PASSWORD ||
248 state == State::HOSTNAME ||
state == State::PORT) &&
263 if ((
state == State::PROTOCOL ||
state == State::AUTHORITY ||
264 state == State::USERNAME ||
state == State::PASSWORD ||
265 state == State::HOSTNAME ||
state == State::PORT ||
266 state == State::PATHNAME) &&
281template <url_pattern_regex::regex_concept regex_prov
ider>
282std::string constructor_string_parser<regex_provider>::make_component_string() {
301template <url_pattern_regex::regex_concept regex_prov
ider>
303constructor_string_parser<regex_provider>::is_an_identity_terminator()
const {
309template <url_pattern_regex::regex_concept regex_prov
ider>
310constexpr bool constructor_string_parser<regex_provider>::is_pathname_start()
317template <url_pattern_regex::regex_concept regex_prov
ider>
318constexpr bool constructor_string_parser<regex_provider>::is_password_prefix()
325template <url_pattern_regex::regex_concept regex_prov
ider>
326constexpr bool constructor_string_parser<regex_provider>::is_an_ipv6_open()
333template <url_pattern_regex::regex_concept regex_prov
ider>
334constexpr bool constructor_string_parser<regex_provider>::is_an_ipv6_close()
341template <url_pattern_regex::regex_concept regex_prov
ider>
342constexpr bool constructor_string_parser<regex_provider>::is_port_prefix()
349constexpr void Tokenizer::get_next_code_point() {
361 ada_log(
"Tokenizer::get_next_code_point returning ASCII code point=",
364 " input.size()=",
input.size());
367 ada_log(
"Tokenizer::get_next_code_point read first byte=",
372 ada_log(
"Tokenizer::get_next_code_point two bytes");
376 ada_log(
"Tokenizer::get_next_code_point three bytes");
380 ada_log(
"Tokenizer::get_next_code_point four bytes");
385 unsigned char byte =
input[
i];
389 ada_log(
"Tokenizer::get_next_code_point returning non-ASCII code point=",
392 " input.size()=",
input.size());
396constexpr void Tokenizer::seek_and_get_next_code_point(
size_t new_index) {
397 ada_log(
"Tokenizer::seek_and_get_next_code_point called with new_index=",
423inline void Tokenizer::add_token_with_default_length(
token_type type,
433inline void Tokenizer::add_token_with_defaults(
token_type type) {
434 ada_log(
"Tokenizer::add_token_with_defaults called with type=",
445 if (
policy == token_policy::strict) {
446 ada_log(
"process_tokenizing_error failed with next_position=",
459template <url_pattern_encoding_callback F>
460token* url_pattern_parser<F>::try_consume_modifier_token() {
472template <url_pattern_encoding_callback F>
473token* url_pattern_parser<F>::try_consume_regexp_or_wildcard_token(
487template <url_pattern_encoding_callback F>
489 ada_log(
"url_pattern_parser::try_consume_token called with type=",
503template <url_pattern_encoding_callback F>
504std::string url_pattern_parser<F>::consume_text() {
524template <url_pattern_encoding_callback F>
525bool url_pattern_parser<F>::consume_required_token(
token_type type) {
526 ada_log(
"url_pattern_parser::consume_required_token called with type=",
533template <url_pattern_encoding_callback F>
535url_pattern_parser<F>::maybe_add_part_from_the_pending_fixed_value() {
538 ada_log(
"pending_fixed_value is empty");
553 parts.emplace_back(url_pattern_part_type::FIXED_TEXT,
555 url_pattern_part_modifier::none);
559template <url_pattern_encoding_callback F>
560std::optional<errors> url_pattern_parser<F>::add_part(
564 auto modifier = url_pattern_part_modifier::none;
569 modifier = url_pattern_part_modifier::optional;
573 modifier = url_pattern_part_modifier::zero_or_more;
577 modifier = url_pattern_part_modifier::one_or_more;
583 modifier == url_pattern_part_modifier::none) {
597 if (
prefix.empty())
return std::nullopt;
607 parts.emplace_back(url_pattern_part_type::FIXED_TEXT,
626 auto type = url_pattern_part_type::REGEXP;
630 type = url_pattern_part_type::SEGMENT_WILDCARD;
636 type = url_pattern_part_type::FULL_WILDCARD;
654 if (std::ranges::any_of(
675template <url_pattern_encoding_callback F>
689 ada_log(
"parse_pattern_string tokenize failed");
695 while (parser.can_continue()) {
698 auto char_token = parser.try_consume_token(token_type::CHAR);
701 auto name_token = parser.try_consume_token(token_type::NAME);
705 parser.try_consume_regexp_or_wildcard_token(
name_token);
715 parser.pending_fixed_value.append(
prefix);
720 if (
auto error = parser.maybe_add_part_from_the_pending_fixed_value()) {
721 ada_log(
"maybe_add_part_from_the_pending_fixed_value failed");
722 return tl::unexpected(*
error);
732 ada_log(
"parser.add_part failed");
733 return tl::unexpected(*
error);
744 fixed_token = parser.try_consume_token(token_type::ESCAPED_CHAR);
748 parser.pending_fixed_value.append(
fixed_token->value);
754 auto open_token = parser.try_consume_token(token_type::OPEN);
758 auto prefix_ = parser.consume_text();
761 name_token = parser.try_consume_token(token_type::NAME);
765 parser.try_consume_regexp_or_wildcard_token(
name_token);
767 auto suffix_ = parser.consume_text();
769 if (!parser.consume_required_token(token_type::CLOSE)) {
770 ada_log(
"parser.consume_required_token failed");
781 return tl::unexpected(*
error);
787 if (
auto error = parser.maybe_add_part_from_the_pending_fixed_value()) {
788 ada_log(
"maybe_add_part_from_the_pending_fixed_value failed on line 992");
789 return tl::unexpected(*
error);
792 if (!parser.consume_required_token(token_type::END)) {
796 ada_log(
"parser.parts size is: ", parser.parts.size());
801template <url_pattern_regex::regex_concept regex_prov
ider>
806 case url_pattern_component_type::EMPTY:
809 case url_pattern_component_type::EXACT_MATCH:
811 return component.exact_match_value ==
"http" ||
812 component.exact_match_value ==
"https" ||
816 case url_pattern_component_type::FULL_WILDCARD:
819 case url_pattern_component_type::REGEXP:
822 return regex_provider::regex_match(
"http",
regex) ||
823 regex_provider::regex_match(
"https",
regex) ||
824 regex_provider::regex_match(
"ws",
regex) ||
825 regex_provider::regex_match(
"wss",
regex) ||
826 regex_provider::regex_match(
"ftp",
regex);
831template <url_pattern_regex::regex_concept regex_prov
ider>
835 "constructor_string_parser::compute_protocol_matches_special_scheme_"
844 url_pattern_compile_component_options::DEFAULT);
846 ada_log(
"url_pattern_component::compile failed for protocol_string ",
859template <url_pattern_regex::regex_concept regex_prov
ider>
860tl::expected<url_pattern_init, errors>
861constructor_string_parser<regex_provider>::parse(std::string_view
input) {
862 ada_log(
"constructor_string_parser::parse input=",
input);
872 while (parser.token_index < parser.token_list.size()) {
874 parser.token_increment = 1;
877 if (parser.token_list[parser.token_index].type == token_type::END) {
879 if (parser.state == State::INIT) {
884 if (parser.is_hash_prefix()) {
885 parser.change_state(State::HASH, 1);
886 }
else if (parser.is_search_prefix()) {
889 parser.change_state(State::SEARCH, 1);
892 parser.change_state(State::PATHNAME, 0);
895 parser.token_index += parser.token_increment;
900 if (parser.state == State::AUTHORITY) {
904 parser.change_state(State::HOSTNAME, 0);
906 parser.token_index += parser.token_increment;
912 parser.change_state(State::DONE, 0);
918 if (parser.is_group_open()) {
920 parser.group_depth += 1;
922 parser.token_index += parser.token_increment;
926 if (parser.group_depth > 0) {
929 if (parser.is_group_close()) {
930 parser.group_depth -= 1;
933 parser.token_index += parser.token_increment;
939 switch (parser.state) {
942 if (parser.is_protocol_suffix()) {
945 parser.change_state(State::PROTOCOL, 0);
949 case State::PROTOCOL: {
951 if (parser.is_protocol_suffix()) {
953 if (
const auto error =
954 parser.compute_protocol_matches_special_scheme_flag()) {
955 ada_log(
"compute_protocol_matches_special_scheme_flag failed");
956 return tl::unexpected(*
error);
964 if (parser.next_is_authority_slashes()) {
969 }
else if (parser.protocol_matches_a_special_scheme_flag) {
980 case State::AUTHORITY: {
983 if (parser.is_an_identity_terminator()) {
985 parser.change_state(State::USERNAME, 0);
986 }
else if (parser.is_pathname_start() || parser.is_search_prefix() ||
987 parser.is_hash_prefix()) {
994 parser.change_state(State::HOSTNAME, 0);
998 case State::USERNAME: {
1001 if (parser.is_password_prefix()) {
1002 parser.change_state(State::PASSWORD, 1);
1003 }
else if (parser.is_an_identity_terminator()) {
1007 parser.change_state(State::HOSTNAME, 1);
1011 case State::PASSWORD: {
1014 if (parser.is_an_identity_terminator()) {
1015 parser.change_state(State::HOSTNAME, 1);
1019 case State::HOSTNAME: {
1022 if (parser.is_an_ipv6_open()) {
1023 parser.hostname_ipv6_bracket_depth += 1;
1024 }
else if (parser.is_an_ipv6_close()) {
1027 parser.hostname_ipv6_bracket_depth -= 1;
1028 }
else if (parser.is_port_prefix() &&
1029 parser.hostname_ipv6_bracket_depth == 0) {
1033 parser.change_state(State::PORT, 1);
1034 }
else if (parser.is_pathname_start()) {
1037 parser.change_state(State::PATHNAME, 0);
1038 }
else if (parser.is_search_prefix()) {
1041 parser.change_state(State::SEARCH, 1);
1042 }
else if (parser.is_hash_prefix()) {
1045 parser.change_state(State::HASH, 1);
1053 if (parser.is_pathname_start()) {
1054 parser.change_state(State::PATHNAME, 0);
1055 }
else if (parser.is_search_prefix()) {
1058 parser.change_state(State::SEARCH, 1);
1059 }
else if (parser.is_hash_prefix()) {
1062 parser.change_state(State::HASH, 1);
1066 case State::PATHNAME: {
1069 if (parser.is_search_prefix()) {
1070 parser.change_state(State::SEARCH, 1);
1071 }
else if (parser.is_hash_prefix()) {
1074 parser.change_state(State::HASH, 1);
1078 case State::SEARCH: {
1081 if (parser.is_hash_prefix()) {
1082 parser.change_state(State::HASH, 1);
1097 parser.token_index += parser.token_increment;
1102 if (parser.result.hostname && !parser.result.port) {
1103 parser.result.port =
"";
1107 return parser.result;
Cross-platform compiler macros and common definitions.
#define ADA_ASSERT_TRUE(COND)
User-facing functions for URL parsing and manipulation.
type
Enumeration of URL scheme types.
errors
Error codes for URL parsing operations.
state
States in the URL parsing state machine.
tl::expected< result_type, ada::errors > result
ada_warn_unused std::string_view to_string(encoding_type type)
ada_warn_unused ada::result< result_type > parse(std::string_view input, const result_type *base_url=nullptr)
ada::url_pattern_regex::std_regex_provider regex_provider
Declaration for the URLPattern helpers.