15template <
bool has_state_overr
ide>
17 const std::string_view input_with_colon) {
18 ada_log(
"url_aggregator::parse_scheme_with_colon ", input_with_colon);
21 std::string_view input{input_with_colon};
22 input.remove_suffix(1);
29 if (is_input_special) {
30 if (has_state_override) {
53 set_scheme_from_view_with_colon(input_with_colon);
55 if (has_state_override) {
61 if (components.
port == urls_scheme_port) {
66 std::string _buffer(input);
70 unicode::to_lower_ascii(_buffer.data(), _buffer.size());
72 if (has_state_override) {
76 if (
is_special() != ada::scheme::is_special(_buffer)) {
97 if (has_state_override) {
103 if (components.
port == urls_scheme_port) {
112inline void url_aggregator::copy_scheme(
const url_aggregator& u)
noexcept {
113 ada_log(
"url_aggregator::copy_scheme ", u.buffer);
117 uint32_t new_difference = u.components.protocol_end - components.protocol_end;
119 buffer.erase(0, components.protocol_end);
120 buffer.insert(0, u.get_protocol());
121 components.protocol_end = u.components.protocol_end;
124 if (new_difference == 0) {
129 components.username_end += new_difference;
130 components.host_start += new_difference;
131 components.host_end += new_difference;
132 components.pathname_start += new_difference;
134 components.search_start += new_difference;
137 components.hash_start += new_difference;
142inline void url_aggregator::set_scheme_from_view_with_colon(
143 std::string_view new_scheme_with_colon)
noexcept {
144 ada_log(
"url_aggregator::set_scheme_from_view_with_colon ",
145 new_scheme_with_colon);
148 new_scheme_with_colon.back() ==
':');
151 uint32_t new_difference =
152 uint32_t(new_scheme_with_colon.size()) - components.protocol_end;
154 if (buffer.empty()) {
155 buffer.append(new_scheme_with_colon);
157 buffer.erase(0, components.protocol_end);
158 buffer.insert(0, new_scheme_with_colon);
160 components.protocol_end += new_difference;
163 components.username_end += new_difference;
164 components.host_start += new_difference;
165 components.host_end += new_difference;
166 components.pathname_start += new_difference;
168 components.search_start += new_difference;
171 components.hash_start += new_difference;
176inline void url_aggregator::set_scheme(std::string_view new_scheme)
noexcept {
177 ada_log(
"url_aggregator::set_scheme ", new_scheme);
182 uint32_t new_difference =
183 uint32_t(new_scheme.size()) - components.protocol_end + 1;
186 if (buffer.empty()) {
187 buffer.append(helpers::concat(new_scheme,
":"));
189 buffer.erase(0, components.protocol_end);
190 buffer.insert(0, helpers::concat(new_scheme,
":"));
192 components.protocol_end = uint32_t(new_scheme.size() + 1);
195 components.username_end += new_difference;
196 components.host_start += new_difference;
197 components.host_end += new_difference;
198 components.pathname_start += new_difference;
200 components.search_start += new_difference;
203 components.hash_start += new_difference;
209 ada_log(
"url_aggregator::set_protocol ", input);
212 std::string view(input);
213 helpers::remove_ascii_tab_or_newline(view);
225 std::string::iterator pointer =
226 std::find_if_not(view.begin(), view.end(), unicode::is_alnum_plus);
228 if (pointer != view.end() && *pointer ==
':') {
229 return parse_scheme_with_colon<true>(
230 std::string_view(view.data(), pointer - view.begin() + 1));
236 ada_log(
"url_aggregator::set_username '", input,
"' ");
239 if (cannot_have_credentials_or_port()) {
244 if (idx == input.size()) {
245 update_base_username(input);
248 update_base_username(ada::unicode::percent_encode(
256 ada_log(
"url_aggregator::set_password '", input,
"'");
259 if (cannot_have_credentials_or_port()) {
264 if (idx == input.size()) {
265 update_base_password(input);
268 update_base_password(ada::unicode::percent_encode(
276 ada_log(
"url_aggregator::set_port ", input);
279 if (cannot_have_credentials_or_port()) {
282 std::string trimmed(input);
283 helpers::remove_ascii_tab_or_newline(trimmed);
284 if (trimmed.empty()) {
289 if (ada::unicode::is_c0_control_or_space(trimmed.front())) {
293 if (input.find_first_of(
"0123456789") == std::string_view::npos) {
298 uint32_t previous_port = components.
port;
303 update_base_port(previous_port);
310 ada_log(
"url_aggregator::set_pathname ", input);
318 if (
get_pathname().starts_with(
"//") && !has_authority() && !has_dash_dot()) {
327 ada_log(
"url_aggregator::parse_path ", input);
330 std::string tmp_buffer;
331 std::string_view internal_input;
332 if (unicode::has_tabs_or_newline(input)) {
336 helpers::remove_ascii_tab_or_newline(tmp_buffer);
337 internal_input = tmp_buffer;
339 internal_input = input;
344 if (internal_input.empty()) {
345 update_base_pathname(
"/");
346 }
else if ((internal_input[0] ==
'/') || (internal_input[0] ==
'\\')) {
347 consume_prepared_path(internal_input.substr(1));
349 consume_prepared_path(internal_input);
351 }
else if (!internal_input.empty()) {
352 if (internal_input[0] ==
'/') {
353 consume_prepared_path(internal_input.substr(1));
355 consume_prepared_path(internal_input);
361 update_base_pathname(
"/");
368 ada_log(
"url_aggregator::set_search ", input);
373 helpers::strip_trailing_spaces_from_opaque_path(*
this);
377 std::string new_value;
378 new_value = input[0] ==
'?' ? input.substr(1) : input;
379 helpers::remove_ascii_tab_or_newline(new_value);
381 auto query_percent_encode_set =
385 update_base_search(new_value, query_percent_encode_set);
390 ada_log(
"url_aggregator::set_hash ", input);
398 helpers::strip_trailing_spaces_from_opaque_path(*
this);
402 std::string new_value;
403 new_value = input[0] ==
'#' ? input.substr(1) : input;
404 helpers::remove_ascii_tab_or_newline(new_value);
405 update_unencoded_base_hash(new_value);
411 ada_log(
"url_aggregator::set_href ", input,
" [", input.size(),
" bytes]");
413 ada_log(
"url_aggregator::set_href, success :", out.has_value());
416 ada_log(
"url_aggregator::set_href, parsed ", out->to_string());
421 return out.has_value();
425 ada_log(
"url_aggregator:parse_host \"", input,
"\" [", input.size(),
433 if (input[0] ==
'[') {
435 if (input.back() !=
']') {
438 ada_log(
"parse_host ipv6");
442 input.remove_prefix(1);
443 input.remove_suffix(1);
444 return parse_ipv6(input);
450 return parse_opaque_host(input);
461 uint8_t is_forbidden_or_upper =
462 unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
470 if (is_forbidden_or_upper == 0 &&
471 input.find(
"xn-") == std::string_view::npos) {
473 update_base_hostname(input);
475 ada_log(
"parse_host fast path ipv4");
485 ada_log(
"parse_host calling to_ascii");
486 std::optional<std::string> host = std::string(
get_hostname());
487 is_valid = ada::unicode::to_ascii(host, input, input.find(
'%'));
489 ada_log(
"parse_host to_ascii returns false");
492 ada_log(
"parse_host to_ascii succeeded ", *host,
" [", host->size(),
495 if (std::any_of(host.value().begin(), host.value().end(),
496 ada::unicode::is_forbidden_domain_code_point)) {
502 if (checkers::is_ipv4(host.value())) {
503 ada_log(
"parse_host got ipv4 ", *host);
504 return parse_ipv4(host.value(),
false);
507 update_base_hostname(host.value());
512template <
bool overr
ide_hostname>
513bool url_aggregator::set_host_or_hostname(
const std::string_view input) {
514 ada_log(
"url_aggregator::set_host_or_hostname ", input);
522 uint32_t previous_port = components.
port;
524 size_t host_end_pos = input.find(
'#');
525 std::string _host(input.data(), host_end_pos != std::string_view::npos
528 helpers::remove_ascii_tab_or_newline(_host);
529 std::string_view new_host(_host);
534 std::string_view host_view(_host.data(), _host.length());
535 auto [location, found_colon] =
536 helpers::get_host_delimiter_location(
is_special(), host_view);
542 if (override_hostname) {
545 std::string_view sub_buffer = new_host.substr(location + 1);
546 if (!sub_buffer.empty()) {
554 else if (host_view.empty() &&
563 }
else if (has_dash_dot()) {
564 add_authority_slashes_if_needed();
570 bool succeeded = parse_host(host_view);
572 update_base_hostname(previous_host);
573 update_base_port(previous_port);
574 }
else if (has_dash_dot()) {
581 size_t location = new_host.find_first_of(
"/\\?");
582 if (location != std::string_view::npos) {
583 new_host.remove_suffix(new_host.length() - location);
586 if (new_host.empty()) {
591 if (!parse_host(new_host)) {
592 update_base_hostname(previous_host);
593 update_base_port(previous_port);
598 if (helpers::substring(buffer, components.
host_start,
599 components.
host_end) ==
"localhost") {
608 ada_log(
"url_aggregator::set_host '", input,
"'");
611 return set_host_or_hostname<false>(input);
615 ada_log(
"url_aggregator::set_hostname '", input,
"'");
618 return set_host_or_hostname<true>(input);
622 ada_log(
"url_aggregator::get_origin");
639 return helpers::concat(out->get_protocol(),
"//", out->get_host());
650 ada_log(
"url_aggregator::get_username");
652 return helpers::substring(buffer, components.
protocol_end + 2,
660 ada_log(
"url_aggregator::get_password");
662 return helpers::substring(buffer, components.
username_end + 1,
670 ada_log(
"url_aggregator::get_port");
674 return helpers::substring(buffer, components.
host_end + 1,
680 ada_log(
"url_aggregator::get_hash");
686 if (buffer.size() - components.
hash_start <= 1) {
689 return helpers::substring(buffer, components.
hash_start);
694 ada_log(
"url_aggregator::get_host");
708 return helpers::substring(buffer, start, components.
pathname_start);
713 ada_log(
"url_aggregator::get_hostname");
723 return helpers::substring(buffer, start, components.
host_end);
728 ada_log(
"url_aggregator::get_pathname pathname_start = ",
731 " components.hash_start = ", components.
hash_start);
732 auto ending_index = uint32_t(buffer.size());
738 return helpers::substring(buffer, components.
pathname_start, ending_index);
743 ada_log(
"url_aggregator::get_search");
749 auto ending_index = uint32_t(buffer.size());
756 return helpers::substring(buffer, components.
search_start, ending_index);
761 ada_log(
"url_aggregator::get_protocol");
762 return helpers::substring(buffer, 0, components.
protocol_end);
766 ada_log(
"url_aggregator::to_string buffer:", buffer,
" [", buffer.size(),
773 auto back = std::back_insert_iterator(answer);
774 answer.append(
"{\n");
776 answer.append(
"\t\"buffer\":\"");
777 helpers::encode_json(buffer, back);
778 answer.append(
"\",\n");
780 answer.append(
"\t\"protocol\":\"");
781 helpers::encode_json(get_protocol(), back);
782 answer.append(
"\",\n");
784 if (has_credentials()) {
785 answer.append(
"\t\"username\":\"");
786 helpers::encode_json(get_username(), back);
787 answer.append(
"\",\n");
788 answer.append(
"\t\"password\":\"");
789 helpers::encode_json(get_password(), back);
790 answer.append(
"\",\n");
793 answer.append(
"\t\"host\":\"");
794 helpers::encode_json(get_host(), back);
795 answer.append(
"\",\n");
797 answer.append(
"\t\"path\":\"");
798 helpers::encode_json(get_pathname(), back);
799 answer.append(
"\",\n");
800 answer.append(
"\t\"opaque path\":");
801 answer.append((has_opaque_path ?
"true" :
"false"));
802 answer.append(
",\n");
805 answer.append(
"\t\"query\":\"");
806 helpers::encode_json(get_search(), back);
807 answer.append(
"\",\n");
810 answer.append(
"\t\"fragment\":\"");
811 helpers::encode_json(get_hash(), back);
812 answer.append(
"\",\n");
815 auto convert_offset_to_string = [](uint32_t offset) -> std::string {
819 return std::to_string(offset);
823 answer.append(
"\t\"protocol_end\":");
824 answer.append(convert_offset_to_string(components.protocol_end));
825 answer.append(
",\n");
827 answer.append(
"\t\"username_end\":");
828 answer.append(convert_offset_to_string(components.username_end));
829 answer.append(
",\n");
831 answer.append(
"\t\"host_start\":");
832 answer.append(convert_offset_to_string(components.host_start));
833 answer.append(
",\n");
835 answer.append(
"\t\"host_end\":");
836 answer.append(convert_offset_to_string(components.host_end));
837 answer.append(
",\n");
839 answer.append(
"\t\"port\":");
840 answer.append(convert_offset_to_string(components.port));
841 answer.append(
",\n");
843 answer.append(
"\t\"pathname_start\":");
844 answer.append(convert_offset_to_string(components.pathname_start));
845 answer.append(
",\n");
847 answer.append(
"\t\"search_start\":");
848 answer.append(convert_offset_to_string(components.search_start));
849 answer.append(
",\n");
851 answer.append(
"\t\"hash_start\":");
852 answer.append(convert_offset_to_string(components.hash_start));
853 answer.append(
"\n}");
865bool url_aggregator::parse_ipv4(std::string_view input,
bool in_place) {
866 ada_log(
"parse_ipv4 ", input,
" [", input.size(),
867 " bytes], overlaps with buffer: ",
868 helpers::overlaps(input, buffer) ?
"yes" :
"no");
870 const bool trailing_dot = (input.back() ==
'.');
872 input.remove_suffix(1);
874 size_t digit_count{0};
875 int pure_decimal_count = 0;
878 for (; (digit_count < 4) && !(input.empty()); digit_count++) {
882 if (is_hex && ((input.length() == 2) ||
883 ((input.length() > 2) && (input[2] ==
'.')))) {
886 input.remove_prefix(2);
888 std::from_chars_result r{};
890 ada_log(
"parse_ipv4 trying to parse hex number");
891 r = std::from_chars(input.data() + 2, input.data() + input.size(),
893 }
else if ((input.length() >= 2) && input[0] ==
'0' &&
895 ada_log(
"parse_ipv4 trying to parse octal number");
896 r = std::from_chars(input.data() + 1, input.data() + input.size(),
899 ada_log(
"parse_ipv4 trying to parse decimal number");
900 pure_decimal_count++;
901 r = std::from_chars(input.data(), input.data() + input.size(),
904 if (r.ec != std::errc()) {
905 ada_log(
"parse_ipv4 parsing failed");
908 ada_log(
"parse_ipv4 parsed ", segment_result);
909 input.remove_prefix(r.ptr - input.data());
915 if (segment_result >= (uint64_t(1) << (32 - digit_count * 8))) {
918 ipv4 <<= (32 - digit_count * 8);
919 ipv4 |= segment_result;
924 if ((segment_result > 255) || (input[0] !=
'.')) {
928 ipv4 |= segment_result;
929 input.remove_prefix(1);
932 if ((digit_count != 4) || (!input.empty())) {
933 ada_log(
"parse_ipv4 found invalid (more than 4 numbers or empty) ");
937 ada_log(
"url_aggregator::parse_ipv4 completed ",
get_href(),
941 if (in_place && pure_decimal_count == 4 && !trailing_dot) {
943 "url_aggregator::parse_ipv4 completed and was already correct in the "
948 ada_log(
"url_aggregator::parse_ipv4 completed and we need to update it");
953 update_base_hostname(
961bool url_aggregator::parse_ipv6(std::string_view input) {
966 ada_log(
"parse_ipv6 ", input,
" [", input.size(),
" bytes]");
973 std::array<uint16_t, 8> address{};
979 std::optional<int> compress{};
982 std::string_view::iterator pointer = input.begin();
985 if (input[0] ==
':') {
988 if (input.size() == 1 || input[1] !=
':') {
989 ada_log(
"parse_ipv6 starts with : but the rest does not start with :");
997 compress = ++piece_index;
1001 while (pointer != input.end()) {
1003 if (piece_index == 8) {
1004 ada_log(
"parse_ipv6 piece_index == 8");
1009 if (*pointer ==
':') {
1011 if (compress.has_value()) {
1012 ada_log(
"parse_ipv6 compress is non-null");
1019 compress = ++piece_index;
1024 uint16_t value = 0, length = 0;
1029 while (length < 4 && pointer != input.end() &&
1030 unicode::is_ascii_hex_digit(*pointer)) {
1032 value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
1038 if (pointer != input.end() && *pointer ==
'.') {
1041 ada_log(
"parse_ipv6 length is 0");
1049 if (piece_index > 6) {
1050 ada_log(
"parse_ipv6 piece_index > 6");
1055 int numbers_seen = 0;
1058 while (pointer != input.end()) {
1060 std::optional<uint16_t> ipv4_piece{};
1063 if (numbers_seen > 0) {
1066 if (*pointer ==
'.' && numbers_seen < 4) {
1070 ada_log(
"parse_ipv6 Otherwise, validation error, return failure");
1078 "parse_ipv6 If c is not an ASCII digit, validation error, return "
1086 int number = *pointer -
'0';
1089 if (!ipv4_piece.has_value()) {
1090 ipv4_piece = number;
1093 else if (ipv4_piece == 0) {
1094 ada_log(
"parse_ipv6 if ipv4Piece is 0, validation error");
1099 ipv4_piece = *ipv4_piece * 10 + number;
1103 if (ipv4_piece > 255) {
1104 ada_log(
"parse_ipv6 ipv4_piece > 255");
1115 address[piece_index] =
1116 uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
1122 if (numbers_seen == 2 || numbers_seen == 4) {
1128 if (numbers_seen != 4) {
1136 else if ((pointer != input.end()) && (*pointer ==
':')) {
1141 if (pointer == input.end()) {
1143 "parse_ipv6 If c is the EOF code point, validation error, return "
1150 else if (pointer != input.end()) {
1152 "parse_ipv6 Otherwise, if c is not the EOF code point, validation "
1153 "error, return failure");
1158 address[piece_index] = value;
1165 if (compress.has_value()) {
1167 int swaps = piece_index - *compress;
1175 while (piece_index != 0 && swaps > 0) {
1176 std::swap(address[piece_index], address[*compress + swaps - 1]);
1183 else if (piece_index != 8) {
1185 "parse_ipv6 if compress is null and pieceIndex is not 8, validation "
1186 "error, return failure");
1199bool url_aggregator::parse_opaque_host(std::string_view input) {
1200 ada_log(
"parse_opaque_host ", input,
" [", input.size(),
" bytes]");
1203 if (std::any_of(input.begin(), input.end(),
1204 ada::unicode::is_forbidden_host_code_point)) {
1212 if (idx == input.size()) {
1213 update_base_hostname(input);
1216 update_base_hostname(ada::unicode::percent_encode(
1228 answer.append(buffer);
1229 answer.append(
" [");
1230 answer.append(std::to_string(buffer.size()));
1231 answer.append(
" bytes]");
1232 answer.append(
"\n");
1235 line1.resize(buffer.size(),
' ');
1245 if (components.
host_end != buffer.size()) {
1248 if (components.
host_start != buffer.size()) {
1257 answer.append(line1);
1258 answer.append(
"\n");
1260 std::string line2 = line1;
1265 for (
size_t i = components.
hash_start + 1; i < line2.size(); i++) {
1268 line2.append(
" hash_start");
1269 answer.append(line2);
1270 answer.append(
"\n");
1273 std::string line3 = line1;
1278 for (
size_t i = components.
search_start + 1; i < line3.size(); i++) {
1281 line3.append(
" search_start ");
1283 answer.append(line3);
1284 answer.append(
"\n");
1287 std::string line4 = line1;
1291 for (
size_t i = components.
pathname_start + 1; i < line4.size(); i++) {
1294 line4.append(
" pathname_start ");
1296 answer.append(line4);
1297 answer.append(
"\n");
1300 std::string line5 = line1;
1301 if (components.
host_end != buffer.size()) {
1305 for (
size_t i = components.
host_end + 1; i < line5.size(); i++) {
1308 line5.append(
" host_end ");
1309 line5.append(std::to_string(components.
host_end));
1310 answer.append(line5);
1311 answer.append(
"\n");
1314 std::string line6 = line1;
1315 if (components.
host_start != buffer.size()) {
1319 for (
size_t i = components.
host_start + 1; i < line6.size(); i++) {
1322 line6.append(
" host_start ");
1323 line6.append(std::to_string(components.
host_start));
1324 answer.append(line6);
1325 answer.append(
"\n");
1328 std::string line7 = line1;
1333 for (
size_t i = components.
username_end + 1; i < line7.size(); i++) {
1336 line7.append(
" username_end ");
1338 answer.append(line7);
1339 answer.append(
"\n");
1342 std::string line8 = line1;
1347 for (
size_t i = components.
protocol_end + 1; i < line8.size(); i++) {
1350 line8.append(
" protocol_end ");
1352 answer.append(line8);
1353 answer.append(
"\n");
1357 answer.append(
"note: hash omitted\n");
1360 answer.append(
"note: search omitted\n");
1363 answer.append(
"warning: protocol_end overflows\n");
1366 answer.append(
"warning: username_end overflows\n");
1369 answer.append(
"warning: host_start overflows\n");
1371 if (components.
host_end > buffer.size()) {
1372 answer.append(
"warning: host_end overflows\n");
1375 answer.append(
"warning: pathname_start overflows\n");
1385 ada_log(
"url_aggregator::validate inconsistent components \n",
1404 ada_log(
"url_aggregator::validate omitted protocol_end \n",
to_diagram());
1408 ada_log(
"url_aggregator::validate omitted username_end \n",
to_diagram());
1412 ada_log(
"url_aggregator::validate omitted host_start \n",
to_diagram());
1416 ada_log(
"url_aggregator::validate omitted host_end \n",
to_diagram());
1420 ada_log(
"url_aggregator::validate omitted pathname_start \n",
to_diagram());
1425 ada_log(
"url_aggregator::validate protocol_end overflow \n",
to_diagram());
1429 ada_log(
"url_aggregator::validate username_end overflow \n",
to_diagram());
1433 ada_log(
"url_aggregator::validate host_start overflow \n",
to_diagram());
1436 if (components.
host_end > buffer.size()) {
1437 ada_log(
"url_aggregator::validate host_end overflow \n",
to_diagram());
1441 ada_log(
"url_aggregator::validate pathname_start overflow \n",
1449 "url_aggregator::validate missing : at the end of the protocol \n",
1460 "url_aggregator::validate missing : or @ at the end of the username "
1467 if (components.
host_start != buffer.size()) {
1471 "url_aggregator::validate missing @ at the end of the password \n",
1481 "url_aggregator::validate missing // between protocol and host "
1490 "url_aggregator::validate missing @ at the end of the username "
1498 ada_log(
"url_aggregator::validate expected omitted host \n",
1504 if (components.
host_end != buffer.size() &&
1507 buffer[components.
host_end] ==
'/' &&
1508 buffer[components.
host_end + 1] ==
'.') {
1513 "url_aggregator::validate expected the path to begin with // \n",
1517 }
else if (buffer[components.
host_end] !=
':') {
1518 ada_log(
"url_aggregator::validate missing : at the port \n",
1527 ada_log(
"url_aggregator::validate missing / at the path \n",
1534 ada_log(
"url_aggregator::validate missing ? at the search \n",
1541 ada_log(
"url_aggregator::validate missing # at the hash \n",
1550void url_aggregator::delete_dash_dot() {
1551 ada_log(
"url_aggregator::delete_dash_dot");
1554 buffer.erase(components.
host_end, 2);
1566inline void url_aggregator::consume_prepared_path(std::string_view input) {
1567 ada_log(
"url_aggregator::consume_prepared_path ", input);
1577 uint8_t accumulator = checkers::path_signature(input);
1582 constexpr uint8_t need_encoding = 1;
1583 constexpr uint8_t backslash_char = 2;
1584 constexpr uint8_t dot_char = 4;
1585 constexpr uint8_t percent_char = 8;
1590 (special ? (accumulator == 0)
1591 : ((accumulator & (need_encoding | dot_char | percent_char)) ==
1593 (!may_need_slow_file_handling);
1594 if (accumulator == dot_char && !may_need_slow_file_handling) {
1602 if (input[0] !=
'.') {
1603 size_t slashdot = input.find(
"/.");
1604 if (slashdot == std::string_view::npos) {
1605 trivial_path =
true;
1609 !(slashdot + 2 == input.size() || input[slashdot + 2] ==
'.' ||
1610 input[slashdot + 2] ==
'/');
1614 if (trivial_path && is_at_path()) {
1615 ada_log(
"parse_path trivial");
1627 (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
1630 ada_log(
"parse_prepared_path fast");
1635 size_t previous_location = 0;
1637 size_t new_location = input.find(
'/', previous_location);
1640 if (new_location == std::string_view::npos) {
1641 std::string_view path_view = input.substr(previous_location);
1642 if (path_view ==
"..") {
1646 update_base_pathname(path);
1650 if (path.back() ==
'/') {
1651 update_base_pathname(path);
1656 path.resize(path.rfind(
'/') + 1);
1657 update_base_pathname(path);
1661 if (path_view !=
".") {
1662 path.append(path_view);
1664 update_base_pathname(path);
1668 std::string_view path_view =
1669 input.substr(previous_location, new_location - previous_location);
1670 previous_location = new_location + 1;
1671 if (path_view ==
"..") {
1672 size_t last_delimiter = path.rfind(
'/');
1673 if (last_delimiter != std::string::npos) {
1674 path.erase(last_delimiter);
1676 }
else if (path_view !=
".") {
1678 path.append(path_view);
1683 ada_log(
"parse_path slow");
1685 bool needs_percent_encoding = (accumulator & 1);
1686 std::string path_buffer_tmp;
1688 size_t location = (special && (accumulator & 2))
1689 ? input.find_first_of(
"/\\")
1691 std::string_view path_view = input;
1692 if (location != std::string_view::npos) {
1693 path_view.remove_suffix(path_view.size() - location);
1694 input.remove_prefix(location + 1);
1698 std::string_view path_buffer =
1699 (needs_percent_encoding &&
1700 ada::unicode::percent_encode<false>(
1704 if (unicode::is_double_dot_path_segment(path_buffer)) {
1705 if ((helpers::shorten_path(path, type) || special) &&
1706 location == std::string_view::npos) {
1709 }
else if (unicode::is_single_dot_path_segment(path_buffer) &&
1710 (location == std::string_view::npos)) {
1714 else if (!unicode::is_single_dot_path_segment(path_buffer)) {
1721 path += path_buffer[0];
1723 path_buffer.remove_prefix(2);
1724 path.append(path_buffer);
1728 path.append(path_buffer);
1731 if (location == std::string_view::npos) {
1732 update_base_pathname(path);
Includes all definitions for Ada.
Definitions for URL specific checkers used within Ada.
#define ADA_ASSERT_TRUE(COND)
#define ada_lifetime_bound
#define ada_really_inline
Definitions for helper functions used within Ada.
Definitions for user facing functions for parsing URL and it's components.
constexpr uint8_t QUERY_PERCENT_ENCODE[32]
constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32]
constexpr uint8_t PATH_PERCENT_ENCODE[32]
constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32]
constexpr uint8_t USERINFO_PERCENT_ENCODE[32]
constexpr bool has_hex_prefix(std::string_view input)
constexpr bool is_windows_drive_letter(std::string_view input) noexcept
constexpr bool is_alpha(char x) noexcept
constexpr bool is_digit(char x) noexcept
constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept
constexpr uint16_t get_special_port(std::string_view scheme) noexcept
std::string ipv6(const std::array< uint16_t, 8 > &address) noexcept
std::string ipv4(uint64_t address) noexcept
ada_really_inline size_t percent_encode_index(const std::string_view input, const uint8_t character_set[])
template ada::result< url_aggregator > parse< url_aggregator >(std::string_view input, const url_aggregator *base_url)
tl::expected< result_type, ada::errors > result
ada_warn_unused ada::result< result_type > parse(std::string_view input, const result_type *base_url=nullptr)
Declarations for the URL scheme.
bool has_non_empty_username() const noexcept
void set_hash(std::string_view input)
void clear_search() override
bool has_hostname() const noexcept
std::string_view get_hostname() const noexcept ada_lifetime_bound
bool has_non_empty_password() const noexcept
ada_really_inline bool has_credentials() const noexcept
std::string to_string() const override
std::string_view get_pathname() const noexcept ada_lifetime_bound
std::string_view get_hash() const noexcept ada_lifetime_bound
std::string to_diagram() const
bool set_protocol(std::string_view input)
std::string get_origin() const noexcept override
bool validate() const noexcept
std::string_view get_search() const noexcept ada_lifetime_bound
bool has_valid_domain() const noexcept override
bool set_hostname(std::string_view input)
bool set_password(std::string_view input)
bool set_pathname(std::string_view input)
std::string_view get_protocol() const noexcept ada_lifetime_bound
std::string_view get_password() const noexcept ada_lifetime_bound
bool set_href(std::string_view input)
void set_search(std::string_view input)
std::string_view get_port() const noexcept ada_lifetime_bound
bool has_port() const noexcept
std::string_view get_href() const noexcept ada_lifetime_bound
bool set_host(std::string_view input)
std::string_view get_host() const noexcept ada_lifetime_bound
bool set_port(std::string_view input)
std::string_view get_username() const noexcept ada_lifetime_bound
bool set_username(std::string_view input)
ada_really_inline bool is_special() const noexcept
bool check_offset_consistency() const noexcept
static constexpr uint32_t omitted
Definitions for unicode operations.
Inline functions for url aggregator.
Declaration for the basic URL definitions.
Declaration for the URL Components.