17template <
bool has_state_overr
ide>
19 const std::string_view input_with_colon) {
20 ada_log(
"url_aggregator::parse_scheme_with_colon ", input_with_colon);
23 std::string_view input{input_with_colon};
24 input.remove_suffix(1);
31 if (is_input_special) {
32 if constexpr (has_state_override) {
49 components.host_start == components.host_end) {
55 set_scheme_from_view_with_colon(input_with_colon);
57 if constexpr (has_state_override) {
59 uint16_t urls_scheme_port = get_special_port();
63 if (components.port == urls_scheme_port) {
68 std::string _buffer(input);
72 unicode::to_lower_ascii(_buffer.data(), _buffer.size());
74 if constexpr (has_state_override) {
78 if (
is_special() != ada::scheme::is_special(_buffer)) {
92 components.host_start == components.host_end) {
99 if constexpr (has_state_override) {
101 uint16_t urls_scheme_port = get_special_port();
105 if (components.port == urls_scheme_port) {
114inline void url_aggregator::copy_scheme(
const url_aggregator& u)
noexcept {
115 ada_log(
"url_aggregator::copy_scheme ", u.buffer);
119 uint32_t new_difference = u.components.protocol_end - components.protocol_end;
121 buffer.erase(0, components.protocol_end);
122 buffer.insert(0, u.get_protocol());
123 components.protocol_end = u.components.protocol_end;
126 if (new_difference == 0) {
131 components.username_end += new_difference;
132 components.host_start += new_difference;
133 components.host_end += new_difference;
134 components.pathname_start += new_difference;
136 components.search_start += new_difference;
139 components.hash_start += new_difference;
144inline void url_aggregator::set_scheme_from_view_with_colon(
145 std::string_view new_scheme_with_colon)
noexcept {
146 ada_log(
"url_aggregator::set_scheme_from_view_with_colon ",
147 new_scheme_with_colon);
150 new_scheme_with_colon.back() ==
':');
153 uint32_t new_difference =
154 uint32_t(new_scheme_with_colon.size()) - components.protocol_end;
156 if (buffer.empty()) {
157 buffer.append(new_scheme_with_colon);
159 buffer.erase(0, components.protocol_end);
160 buffer.insert(0, new_scheme_with_colon);
162 components.protocol_end += new_difference;
165 components.username_end += new_difference;
166 components.host_start += new_difference;
167 components.host_end += new_difference;
168 components.pathname_start += new_difference;
170 components.search_start += new_difference;
173 components.hash_start += new_difference;
178inline void url_aggregator::set_scheme(std::string_view new_scheme)
noexcept {
179 ada_log(
"url_aggregator::set_scheme ", new_scheme);
184 uint32_t new_difference =
185 uint32_t(new_scheme.size()) - components.protocol_end + 1;
188 if (buffer.empty()) {
189 buffer.append(helpers::concat(new_scheme,
":"));
191 buffer.erase(0, components.protocol_end);
192 buffer.insert(0, helpers::concat(new_scheme,
":"));
194 components.protocol_end = uint32_t(new_scheme.size() + 1);
197 components.username_end += new_difference;
198 components.host_start += new_difference;
199 components.host_end += new_difference;
200 components.pathname_start += new_difference;
202 components.search_start += new_difference;
205 components.hash_start += new_difference;
211 ada_log(
"url_aggregator::set_protocol ", input);
214 std::string view(input);
215 helpers::remove_ascii_tab_or_newline(view);
227 std::string::iterator pointer =
228 std::ranges::find_if_not(view, unicode::is_alnum_plus);
230 if (pointer != view.end() && *pointer ==
':') {
231 return parse_scheme_with_colon<true>(
232 view.substr(0, pointer - view.begin() + 1));
238 ada_log(
"url_aggregator::set_username '", input,
"' ");
241 if (cannot_have_credentials_or_port()) {
246 if (idx == input.size()) {
247 update_base_username(input);
250 update_base_username(ada::unicode::percent_encode(
258 ada_log(
"url_aggregator::set_password '", input,
"'");
261 if (cannot_have_credentials_or_port()) {
266 if (idx == input.size()) {
267 update_base_password(input);
270 update_base_password(ada::unicode::percent_encode(
278 ada_log(
"url_aggregator::set_port ", input);
281 if (cannot_have_credentials_or_port()) {
290 std::string trimmed(input);
291 helpers::remove_ascii_tab_or_newline(trimmed);
293 if (trimmed.empty()) {
298 if (!ada::unicode::is_ascii_digit(trimmed.front())) {
303 auto first_non_digit =
304 std::ranges::find_if_not(trimmed, ada::unicode::is_ascii_digit);
305 std::string_view digits_to_parse =
306 std::string_view(trimmed.data(), first_non_digit - trimmed.begin());
309 uint32_t previous_port = components.port;
310 parse_port(digits_to_parse);
314 update_base_port(previous_port);
321 ada_log(
"url_aggregator::set_pathname ", input);
329 if (
get_pathname().starts_with(
"//") && !has_authority() && !has_dash_dot()) {
330 buffer.insert(components.pathname_start,
"/.");
331 components.pathname_start += 2;
338 ada_log(
"url_aggregator::parse_path ", input);
341 std::string tmp_buffer;
342 std::string_view internal_input;
343 if (unicode::has_tabs_or_newline(input)) {
347 helpers::remove_ascii_tab_or_newline(tmp_buffer);
348 internal_input = tmp_buffer;
350 internal_input = input;
355 if (internal_input.empty()) {
356 update_base_pathname(
"/");
357 }
else if ((internal_input[0] ==
'/') || (internal_input[0] ==
'\\')) {
358 consume_prepared_path(internal_input.substr(1));
360 consume_prepared_path(internal_input);
362 }
else if (!internal_input.empty()) {
363 if (internal_input[0] ==
'/') {
364 consume_prepared_path(internal_input.substr(1));
366 consume_prepared_path(internal_input);
371 if (components.host_start == components.host_end && !has_authority()) {
372 update_base_pathname(
"/");
379 ada_log(
"url_aggregator::set_search ", input);
384 helpers::strip_trailing_spaces_from_opaque_path(*
this);
388 std::string new_value;
389 new_value = input[0] ==
'?' ? input.substr(1) : input;
390 helpers::remove_ascii_tab_or_newline(new_value);
392 auto query_percent_encode_set =
396 update_base_search(new_value, query_percent_encode_set);
401 ada_log(
"url_aggregator::set_hash ", input);
406 buffer.resize(components.hash_start);
409 helpers::strip_trailing_spaces_from_opaque_path(*
this);
413 std::string new_value;
414 new_value = input[0] ==
'#' ? input.substr(1) : input;
415 helpers::remove_ascii_tab_or_newline(new_value);
416 update_unencoded_base_hash(new_value);
422 ada_log(
"url_aggregator::set_href ", input,
" [", input.size(),
" bytes]");
424 ada_log(
"url_aggregator::set_href, success :", out.has_value());
427 ada_log(
"url_aggregator::set_href, parsed ", out->to_string());
432 return out.has_value();
436 ada_log(
"url_aggregator:parse_host \"", input,
"\" [", input.size(),
444 if (input[0] ==
'[') {
446 if (input.back() !=
']') {
449 ada_log(
"parse_host ipv6");
453 input.remove_prefix(1);
454 input.remove_suffix(1);
455 return parse_ipv6(input);
461 return parse_opaque_host(input);
477 if (!input.empty() && input.back() ==
'.') {
478 update_base_hostname(input.substr(0, input.size() - 1));
480 update_base_hostname(input);
483 ada_log(
"parse_host fast path decimal ipv4");
487 uint8_t is_forbidden_or_upper =
488 unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
496 if (is_forbidden_or_upper == 0 &&
497 input.find(
"xn-") == std::string_view::npos) {
499 update_base_hostname(input);
503 ada_log(
"parse_host fast path ipv4");
513 ada_log(
"parse_host calling to_ascii");
514 std::optional<std::string> host = std::string(
get_hostname());
515 is_valid = ada::unicode::to_ascii(host, input, input.find(
'%'));
517 ada_log(
"parse_host to_ascii returns false");
520 ada_log(
"parse_host to_ascii succeeded ", *host,
" [", host->size(),
523 if (std::ranges::any_of(host.value(),
524 ada::unicode::is_forbidden_domain_code_point)) {
530 if (checkers::is_ipv4(host.value())) {
531 ada_log(
"parse_host got ipv4 ", *host);
532 return parse_ipv4(host.value(),
false);
535 update_base_hostname(host.value());
540template <
bool overr
ide_hostname>
541bool url_aggregator::set_host_or_hostname(
const std::string_view input) {
542 ada_log(
"url_aggregator::set_host_or_hostname ", input);
550 uint32_t previous_port = components.port;
552 size_t host_end_pos = input.find(
'#');
553 std::string _host(input.data(), host_end_pos != std::string_view::npos
556 helpers::remove_ascii_tab_or_newline(_host);
557 std::string_view new_host(_host);
562 std::string_view host_view(_host.data(), _host.length());
563 auto [location, found_colon] =
564 helpers::get_host_delimiter_location(
is_special(), host_view);
572 std::string_view host_buffer = host_view.substr(0, location);
573 if (host_buffer.empty()) {
579 if constexpr (override_hostname) {
584 bool succeeded = parse_host(host_buffer);
586 update_base_hostname(previous_host);
587 update_base_port(previous_port);
593 std::string_view port_buffer = new_host.substr(location + 1);
594 if (!port_buffer.empty()) {
621 }
else if (has_dash_dot()) {
622 add_authority_slashes_if_needed();
628 bool succeeded = parse_host(host_view);
630 update_base_hostname(previous_host);
631 update_base_port(previous_port);
633 }
else if (has_dash_dot()) {
641 size_t location = new_host.find_first_of(
"/\\?");
642 if (location != std::string_view::npos) {
643 new_host.remove_suffix(new_host.length() - location);
646 if (new_host.empty()) {
651 if (!parse_host(new_host)) {
652 update_base_hostname(previous_host);
653 update_base_port(previous_port);
658 if (helpers::substring(buffer, components.host_start,
659 components.host_end) ==
"localhost") {
668 ada_log(
"url_aggregator::set_host '", input,
"'");
671 return set_host_or_hostname<false>(input);
675 ada_log(
"url_aggregator::set_hostname '", input,
"'");
678 return set_host_or_hostname<true>(input);
682 ada_log(
"url_aggregator::get_origin");
699 return helpers::concat(out->get_protocol(),
"//", out->get_host());
710 ada_log(
"url_aggregator::get_username");
712 return helpers::substring(buffer, components.protocol_end + 2,
713 components.username_end);
720 ada_log(
"url_aggregator::get_password");
722 return helpers::substring(buffer, components.username_end + 1,
723 components.host_start);
730 ada_log(
"url_aggregator::get_port");
734 return helpers::substring(buffer, components.host_end + 1,
735 components.pathname_start);
740 ada_log(
"url_aggregator::get_hash");
746 if (buffer.size() - components.hash_start <= 1) {
749 return helpers::substring(buffer, components.hash_start);
754 ada_log(
"url_aggregator::get_host");
758 size_t start = components.host_start;
759 if (components.host_end > components.host_start &&
760 buffer[components.host_start] ==
'@') {
765 if (start == components.host_end) {
768 return helpers::substring(buffer, start, components.pathname_start);
773 ada_log(
"url_aggregator::get_hostname");
777 size_t start = components.host_start;
779 if (components.host_end > components.host_start &&
780 buffer[components.host_start] ==
'@') {
783 return helpers::substring(buffer, start, components.host_end);
788 ada_log(
"url_aggregator::get_search");
794 auto ending_index = uint32_t(buffer.size());
796 ending_index = components.hash_start;
798 if (ending_index - components.search_start <= 1) {
801 return helpers::substring(buffer, components.search_start, ending_index);
806 ada_log(
"url_aggregator::get_protocol");
807 return helpers::substring(buffer, 0, components.protocol_end);
811 ada_log(
"url_aggregator::to_string buffer:", buffer,
" [", buffer.size(),
818 auto back = std::back_insert_iterator(answer);
819 answer.append(
"{\n");
821 answer.append(
"\t\"buffer\":\"");
822 helpers::encode_json(buffer, back);
823 answer.append(
"\",\n");
825 answer.append(
"\t\"protocol\":\"");
827 answer.append(
"\",\n");
830 answer.append(
"\t\"username\":\"");
832 answer.append(
"\",\n");
833 answer.append(
"\t\"password\":\"");
835 answer.append(
"\",\n");
838 answer.append(
"\t\"host\":\"");
839 helpers::encode_json(
get_host(), back);
840 answer.append(
"\",\n");
842 answer.append(
"\t\"path\":\"");
844 answer.append(
"\",\n");
845 answer.append(
"\t\"opaque path\":");
847 answer.append(
",\n");
850 answer.append(
"\t\"query\":\"");
852 answer.append(
"\",\n");
855 answer.append(
"\t\"fragment\":\"");
856 helpers::encode_json(
get_hash(), back);
857 answer.append(
"\",\n");
860 auto convert_offset_to_string = [](uint32_t offset) -> std::string {
864 return std::to_string(offset);
868 answer.append(
"\t\"protocol_end\":");
869 answer.append(convert_offset_to_string(components.protocol_end));
870 answer.append(
",\n");
872 answer.append(
"\t\"username_end\":");
873 answer.append(convert_offset_to_string(components.username_end));
874 answer.append(
",\n");
876 answer.append(
"\t\"host_start\":");
877 answer.append(convert_offset_to_string(components.host_start));
878 answer.append(
",\n");
880 answer.append(
"\t\"host_end\":");
881 answer.append(convert_offset_to_string(components.host_end));
882 answer.append(
",\n");
884 answer.append(
"\t\"port\":");
885 answer.append(convert_offset_to_string(components.port));
886 answer.append(
",\n");
888 answer.append(
"\t\"pathname_start\":");
889 answer.append(convert_offset_to_string(components.pathname_start));
890 answer.append(
",\n");
892 answer.append(
"\t\"search_start\":");
893 answer.append(convert_offset_to_string(components.search_start));
894 answer.append(
",\n");
896 answer.append(
"\t\"hash_start\":");
897 answer.append(convert_offset_to_string(components.hash_start));
898 answer.append(
"\n}");
904 if (components.host_start == components.host_end) {
910bool url_aggregator::parse_ipv4(std::string_view input,
bool in_place) {
911 ada_log(
"parse_ipv4 ", input,
" [", input.size(),
912 " bytes], overlaps with buffer: ",
913 helpers::overlaps(input, buffer) ?
"yes" :
"no");
915 const bool trailing_dot = (input.back() ==
'.');
917 input.remove_suffix(1);
919 size_t digit_count{0};
920 int pure_decimal_count = 0;
923 for (; (digit_count < 4) && !(input.empty()); digit_count++) {
927 if (is_hex && ((input.length() == 2) ||
928 ((input.length() > 2) && (input[2] ==
'.')))) {
931 input.remove_prefix(2);
933 std::from_chars_result r{};
935 ada_log(
"parse_ipv4 trying to parse hex number");
936 r = std::from_chars(input.data() + 2, input.data() + input.size(),
938 }
else if ((input.length() >= 2) && input[0] ==
'0' &&
940 ada_log(
"parse_ipv4 trying to parse octal number");
941 r = std::from_chars(input.data() + 1, input.data() + input.size(),
944 ada_log(
"parse_ipv4 trying to parse decimal number");
945 pure_decimal_count++;
946 r = std::from_chars(input.data(), input.data() + input.size(),
949 if (r.ec != std::errc()) {
950 ada_log(
"parse_ipv4 parsing failed");
953 ada_log(
"parse_ipv4 parsed ", segment_result);
954 input.remove_prefix(r.ptr - input.data());
960 if (segment_result >= (uint64_t(1) << (32 - digit_count * 8))) {
963 ipv4 <<= (32 - digit_count * 8);
964 ipv4 |= segment_result;
969 if ((segment_result > 255) || (input[0] !=
'.')) {
973 ipv4 |= segment_result;
974 input.remove_prefix(1);
977 if ((digit_count != 4) || (!input.empty())) {
978 ada_log(
"parse_ipv4 found invalid (more than 4 numbers or empty) ");
982 ada_log(
"url_aggregator::parse_ipv4 completed ",
get_href(),
986 if (in_place && pure_decimal_count == 4 && !trailing_dot) {
988 "url_aggregator::parse_ipv4 completed and was already correct in the "
993 ada_log(
"url_aggregator::parse_ipv4 completed and we need to update it");
998 update_base_hostname(
1006bool url_aggregator::parse_ipv6(std::string_view input) {
1011 ada_log(
"parse_ipv6 ", input,
" [", input.size(),
" bytes]");
1014 if (input.empty()) {
1018 std::array<uint16_t, 8> address{};
1021 int piece_index = 0;
1024 std::optional<int> compress{};
1027 std::string_view::iterator pointer = input.begin();
1030 if (input[0] ==
':') {
1033 if (input.size() == 1 || input[1] !=
':') {
1034 ada_log(
"parse_ipv6 starts with : but the rest does not start with :");
1042 compress = ++piece_index;
1046 while (pointer != input.end()) {
1048 if (piece_index == 8) {
1049 ada_log(
"parse_ipv6 piece_index == 8");
1054 if (*pointer ==
':') {
1056 if (compress.has_value()) {
1057 ada_log(
"parse_ipv6 compress is non-null");
1064 compress = ++piece_index;
1069 uint16_t value = 0, length = 0;
1074 while (length < 4 && pointer != input.end() &&
1075 unicode::is_ascii_hex_digit(*pointer)) {
1077 value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
1083 if (pointer != input.end() && *pointer ==
'.') {
1086 ada_log(
"parse_ipv6 length is 0");
1094 if (piece_index > 6) {
1095 ada_log(
"parse_ipv6 piece_index > 6");
1100 int numbers_seen = 0;
1103 while (pointer != input.end()) {
1105 std::optional<uint16_t> ipv4_piece{};
1108 if (numbers_seen > 0) {
1111 if (*pointer ==
'.' && numbers_seen < 4) {
1115 ada_log(
"parse_ipv6 Otherwise, validation error, return failure");
1123 "parse_ipv6 If c is not an ASCII digit, validation error, return "
1131 int number = *pointer -
'0';
1134 if (!ipv4_piece.has_value()) {
1135 ipv4_piece = number;
1138 else if (ipv4_piece == 0) {
1139 ada_log(
"parse_ipv6 if ipv4Piece is 0, validation error");
1144 ipv4_piece = *ipv4_piece * 10 + number;
1148 if (ipv4_piece > 255) {
1149 ada_log(
"parse_ipv6 ipv4_piece > 255");
1160 address[piece_index] =
1161 uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
1167 if (numbers_seen == 2 || numbers_seen == 4) {
1173 if (numbers_seen != 4) {
1181 else if ((pointer != input.end()) && (*pointer ==
':')) {
1186 if (pointer == input.end()) {
1188 "parse_ipv6 If c is the EOF code point, validation error, return "
1195 else if (pointer != input.end()) {
1197 "parse_ipv6 Otherwise, if c is not the EOF code point, validation "
1198 "error, return failure");
1203 address[piece_index] = value;
1210 if (compress.has_value()) {
1212 int swaps = piece_index - *compress;
1220 while (piece_index != 0 && swaps > 0) {
1221 std::swap(address[piece_index], address[*compress + swaps - 1]);
1228 else if (piece_index != 8) {
1230 "parse_ipv6 if compress is null and pieceIndex is not 8, validation "
1231 "error, return failure");
1244bool url_aggregator::parse_opaque_host(std::string_view input) {
1245 ada_log(
"parse_opaque_host ", input,
" [", input.size(),
" bytes]");
1248 if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) {
1256 if (idx == input.size()) {
1257 update_base_hostname(input);
1260 update_base_hostname(ada::unicode::percent_encode(
1272 answer.append(buffer);
1273 answer.append(
" [");
1274 answer.append(std::to_string(buffer.size()));
1275 answer.append(
" bytes]");
1276 answer.append(
"\n");
1279 line1.resize(buffer.size(),
' ');
1281 line1[components.hash_start] =
'|';
1284 line1[components.search_start] =
'|';
1286 if (components.pathname_start != buffer.size()) {
1287 line1[components.pathname_start] =
'|';
1289 if (components.host_end != buffer.size()) {
1290 line1[components.host_end] =
'|';
1292 if (components.host_start != buffer.size()) {
1293 line1[components.host_start] =
'|';
1295 if (components.username_end != buffer.size()) {
1296 line1[components.username_end] =
'|';
1298 if (components.protocol_end != buffer.size()) {
1299 line1[components.protocol_end] =
'|';
1301 answer.append(line1);
1302 answer.append(
"\n");
1304 std::string line2 = line1;
1306 line2[components.hash_start] =
'`';
1307 line1[components.hash_start] =
' ';
1309 for (
size_t i = components.hash_start + 1; i < line2.size(); i++) {
1312 line2.append(
" hash_start");
1313 answer.append(line2);
1314 answer.append(
"\n");
1317 std::string line3 = line1;
1319 line3[components.search_start] =
'`';
1320 line1[components.search_start] =
' ';
1322 for (
size_t i = components.search_start + 1; i < line3.size(); i++) {
1325 line3.append(
" search_start ");
1326 line3.append(std::to_string(components.search_start));
1327 answer.append(line3);
1328 answer.append(
"\n");
1331 std::string line4 = line1;
1332 if (components.pathname_start != buffer.size()) {
1333 line4[components.pathname_start] =
'`';
1334 line1[components.pathname_start] =
' ';
1335 for (
size_t i = components.pathname_start + 1; i < line4.size(); i++) {
1338 line4.append(
" pathname_start ");
1339 line4.append(std::to_string(components.pathname_start));
1340 answer.append(line4);
1341 answer.append(
"\n");
1344 std::string line5 = line1;
1345 if (components.host_end != buffer.size()) {
1346 line5[components.host_end] =
'`';
1347 line1[components.host_end] =
' ';
1349 for (
size_t i = components.host_end + 1; i < line5.size(); i++) {
1352 line5.append(
" host_end ");
1353 line5.append(std::to_string(components.host_end));
1354 answer.append(line5);
1355 answer.append(
"\n");
1358 std::string line6 = line1;
1359 if (components.host_start != buffer.size()) {
1360 line6[components.host_start] =
'`';
1361 line1[components.host_start] =
' ';
1363 for (
size_t i = components.host_start + 1; i < line6.size(); i++) {
1366 line6.append(
" host_start ");
1367 line6.append(std::to_string(components.host_start));
1368 answer.append(line6);
1369 answer.append(
"\n");
1372 std::string line7 = line1;
1373 if (components.username_end != buffer.size()) {
1374 line7[components.username_end] =
'`';
1375 line1[components.username_end] =
' ';
1377 for (
size_t i = components.username_end + 1; i < line7.size(); i++) {
1380 line7.append(
" username_end ");
1381 line7.append(std::to_string(components.username_end));
1382 answer.append(line7);
1383 answer.append(
"\n");
1386 std::string line8 = line1;
1387 if (components.protocol_end != buffer.size()) {
1388 line8[components.protocol_end] =
'`';
1389 line1[components.protocol_end] =
' ';
1391 for (
size_t i = components.protocol_end + 1; i < line8.size(); i++) {
1394 line8.append(
" protocol_end ");
1395 line8.append(std::to_string(components.protocol_end));
1396 answer.append(line8);
1397 answer.append(
"\n");
1401 answer.append(
"note: hash omitted\n");
1404 answer.append(
"note: search omitted\n");
1406 if (components.protocol_end > buffer.size()) {
1407 answer.append(
"warning: protocol_end overflows\n");
1409 if (components.username_end > buffer.size()) {
1410 answer.append(
"warning: username_end overflows\n");
1412 if (components.host_start > buffer.size()) {
1413 answer.append(
"warning: host_start overflows\n");
1415 if (components.host_end > buffer.size()) {
1416 answer.append(
"warning: host_end overflows\n");
1418 if (components.pathname_start > buffer.size()) {
1419 answer.append(
"warning: pathname_start overflows\n");
1424void url_aggregator::delete_dash_dot() {
1425 ada_log(
"url_aggregator::delete_dash_dot");
1428 buffer.erase(components.
host_end, 2);
1440inline void url_aggregator::consume_prepared_path(std::string_view input) {
1441 ada_log(
"url_aggregator::consume_prepared_path ", input);
1451 uint8_t accumulator = checkers::path_signature(input);
1456 constexpr uint8_t need_encoding = 1;
1457 constexpr uint8_t backslash_char = 2;
1458 constexpr uint8_t dot_char = 4;
1459 constexpr uint8_t percent_char = 8;
1464 (special ? (accumulator == 0)
1465 : ((accumulator & (need_encoding | dot_char | percent_char)) ==
1467 (!may_need_slow_file_handling);
1468 if (accumulator == dot_char && !may_need_slow_file_handling) {
1476 if (input[0] !=
'.') {
1477 size_t slashdot = 0;
1478 bool dot_is_file =
true;
1480 slashdot = input.find(
"/.", slashdot);
1481 if (slashdot == std::string_view::npos) {
1486 dot_is_file &= !(slashdot == input.size() || input[slashdot] ==
'.' ||
1487 input[slashdot] ==
'/');
1490 trivial_path = dot_is_file;
1493 if (trivial_path && is_at_path()) {
1494 ada_log(
"parse_path trivial");
1506 (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
1509 ada_log(
"parse_prepared_path fast");
1514 size_t previous_location = 0;
1516 size_t new_location = input.find(
'/', previous_location);
1519 if (new_location == std::string_view::npos) {
1520 std::string_view path_view = input.substr(previous_location);
1521 if (path_view ==
"..") {
1525 update_base_pathname(path);
1529 if (path.back() ==
'/') {
1530 update_base_pathname(path);
1535 path.resize(path.rfind(
'/') + 1);
1536 update_base_pathname(path);
1540 if (path_view !=
".") {
1541 path.append(path_view);
1543 update_base_pathname(path);
1547 std::string_view path_view =
1548 input.substr(previous_location, new_location - previous_location);
1549 previous_location = new_location + 1;
1550 if (path_view ==
"..") {
1551 size_t last_delimiter = path.rfind(
'/');
1552 if (last_delimiter != std::string::npos) {
1553 path.erase(last_delimiter);
1555 }
else if (path_view !=
".") {
1557 path.append(path_view);
1562 ada_log(
"parse_path slow");
1564 bool needs_percent_encoding = (accumulator & 1);
1565 std::string path_buffer_tmp;
1567 size_t location = (special && (accumulator & 2))
1568 ? input.find_first_of(
"/\\")
1570 std::string_view path_view = input;
1571 if (location != std::string_view::npos) {
1572 path_view.remove_suffix(path_view.size() - location);
1573 input.remove_prefix(location + 1);
1577 std::string_view path_buffer =
1578 (needs_percent_encoding &&
1579 ada::unicode::percent_encode<false>(
1583 if (unicode::is_double_dot_path_segment(path_buffer)) {
1584 helpers::shorten_path(path, type);
1585 if (location == std::string_view::npos) {
1588 }
else if (unicode::is_single_dot_path_segment(path_buffer) &&
1589 (location == std::string_view::npos)) {
1593 else if (!unicode::is_single_dot_path_segment(path_buffer)) {
1600 path += path_buffer[0];
1602 path_buffer.remove_prefix(2);
1603 path.append(path_buffer);
1607 path.append(path_buffer);
1610 if (location == std::string_view::npos) {
1611 update_base_pathname(path);
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.
User-facing functions for URL parsing and manipulation.
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 uint64_t ipv4_fast_fail
constexpr bool is_alpha(char x) noexcept
constexpr bool is_digit(char x) noexcept
ada_really_inline constexpr uint64_t try_parse_ipv4_fast(std::string_view input) noexcept
constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept
type
Enumeration of URL scheme types.
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)
URL scheme type definitions and utilities.
Memory-efficient URL representation using a single buffer.
constexpr bool has_non_empty_password() const noexcept
void set_hash(std::string_view input)
constexpr bool validate() const noexcept
void clear_search() override
std::string_view get_hostname() const noexcept ada_lifetime_bound
std::string to_string() const override
std::string_view get_hash() const noexcept ada_lifetime_bound
std::string to_diagram() const
constexpr bool has_hostname() const noexcept
bool set_protocol(std::string_view input)
std::string get_origin() const noexcept override
constexpr std::string_view get_href() const noexcept ada_lifetime_bound
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)
constexpr std::string_view get_pathname() const noexcept ada_lifetime_bound
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
constexpr bool has_port() const noexcept
ada_really_inline constexpr bool has_credentials() const noexcept
bool set_host(std::string_view input)
std::string_view get_host() const noexcept ada_lifetime_bound
bool set_port(std::string_view input)
constexpr bool has_non_empty_username() const noexcept
std::string_view get_username() const noexcept ada_lifetime_bound
bool set_username(std::string_view input)
ada_really_inline constexpr bool is_special() const noexcept
static constexpr uint32_t omitted
Definitions for unicode operations.
Inline functions for url aggregator.
Declaration for the ada::url_aggregator class.
Declaration for the URL Components.