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 constexpr (has_state_override) {
 
   47          components.host_start == components.host_end) {
 
   53    set_scheme_from_view_with_colon(input_with_colon);
 
   55    if constexpr (has_state_override) {
 
   57      uint16_t urls_scheme_port = get_special_port();
 
   61      if (components.port == urls_scheme_port) {
 
   66    std::string _buffer(input);
 
   70    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
 
   72    if constexpr (has_state_override) {
 
   76      if (
is_special() != ada::scheme::is_special(_buffer)) {
 
   90          components.host_start == components.host_end) {
 
   97    if constexpr (has_state_override) {
 
   99      uint16_t urls_scheme_port = get_special_port();
 
  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::ranges::find_if_not(view, 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()) {
 
  290  if (!ada::unicode::is_ascii_digit(trimmed.front())) {
 
  295  uint32_t previous_port = components.port;
 
  300  update_base_port(previous_port);
 
 
  307  ada_log(
"url_aggregator::set_pathname ", input);
 
  315  if (
get_pathname().starts_with(
"//") && !has_authority() && !has_dash_dot()) {
 
  316    buffer.insert(components.pathname_start, 
"/.");
 
  317    components.pathname_start += 2;
 
 
  324  ada_log(
"url_aggregator::parse_path ", input);
 
  327  std::string tmp_buffer;
 
  328  std::string_view internal_input;
 
  329  if (unicode::has_tabs_or_newline(input)) {
 
  333    helpers::remove_ascii_tab_or_newline(tmp_buffer);
 
  334    internal_input = tmp_buffer;
 
  336    internal_input = input;
 
  341    if (internal_input.empty()) {
 
  342      update_base_pathname(
"/");
 
  343    } 
else if ((internal_input[0] == 
'/') || (internal_input[0] == 
'\\')) {
 
  344      consume_prepared_path(internal_input.substr(1));
 
  346      consume_prepared_path(internal_input);
 
  348  } 
else if (!internal_input.empty()) {
 
  349    if (internal_input[0] == 
'/') {
 
  350      consume_prepared_path(internal_input.substr(1));
 
  352      consume_prepared_path(internal_input);
 
  357    if (components.host_start == components.host_end && !has_authority()) {
 
  358      update_base_pathname(
"/");
 
  365  ada_log(
"url_aggregator::set_search ", input);
 
  370    helpers::strip_trailing_spaces_from_opaque_path(*
this);
 
  374  std::string new_value;
 
  375  new_value = input[0] == 
'?' ? input.substr(1) : input;
 
  376  helpers::remove_ascii_tab_or_newline(new_value);
 
  378  auto query_percent_encode_set =
 
  382  update_base_search(new_value, query_percent_encode_set);
 
 
  387  ada_log(
"url_aggregator::set_hash ", input);
 
  392      buffer.resize(components.hash_start);
 
  395    helpers::strip_trailing_spaces_from_opaque_path(*
this);
 
  399  std::string new_value;
 
  400  new_value = input[0] == 
'#' ? input.substr(1) : input;
 
  401  helpers::remove_ascii_tab_or_newline(new_value);
 
  402  update_unencoded_base_hash(new_value);
 
 
  408  ada_log(
"url_aggregator::set_href ", input, 
" [", input.size(), 
" bytes]");
 
  410  ada_log(
"url_aggregator::set_href, success :", out.has_value());
 
  413    ada_log(
"url_aggregator::set_href, parsed ", out->to_string());
 
  418  return out.has_value();
 
 
  422  ada_log(
"url_aggregator:parse_host \"", input, 
"\" [", input.size(),
 
  430  if (input[0] == 
'[') {
 
  432    if (input.back() != 
']') {
 
  435    ada_log(
"parse_host ipv6");
 
  439    input.remove_prefix(1);
 
  440    input.remove_suffix(1);
 
  441    return parse_ipv6(input);
 
  447    return parse_opaque_host(input);
 
  458  uint8_t is_forbidden_or_upper =
 
  459      unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
 
  467  if (is_forbidden_or_upper == 0 &&
 
  468      input.find(
"xn-") == std::string_view::npos) {
 
  470    update_base_hostname(input);
 
  472      ada_log(
"parse_host fast path ipv4");
 
  482  ada_log(
"parse_host calling to_ascii");
 
  483  std::optional<std::string> host = std::string(
get_hostname());
 
  484  is_valid = ada::unicode::to_ascii(host, input, input.find(
'%'));
 
  486    ada_log(
"parse_host to_ascii returns false");
 
  489  ada_log(
"parse_host to_ascii succeeded ", *host, 
" [", host->size(),
 
  492  if (std::any_of(host.value().begin(), host.value().end(),
 
  493                  ada::unicode::is_forbidden_domain_code_point)) {
 
  499  if (checkers::is_ipv4(host.value())) {
 
  500    ada_log(
"parse_host got ipv4 ", *host);
 
  501    return parse_ipv4(host.value(), 
false);
 
  504  update_base_hostname(host.value());
 
  509template <
bool overr
ide_hostname>
 
  510bool url_aggregator::set_host_or_hostname(
const std::string_view input) {
 
  511  ada_log(
"url_aggregator::set_host_or_hostname ", input);
 
  519  uint32_t previous_port = components.port;
 
  521  size_t host_end_pos = input.find(
'#');
 
  522  std::string _host(input.data(), host_end_pos != std::string_view::npos
 
  525  helpers::remove_ascii_tab_or_newline(_host);
 
  526  std::string_view new_host(_host);
 
  531    std::string_view host_view(_host.data(), _host.length());
 
  532    auto [location, found_colon] =
 
  533        helpers::get_host_delimiter_location(
is_special(), host_view);
 
  539      if constexpr (override_hostname) {
 
  542      std::string_view sub_buffer = new_host.substr(location + 1);
 
  543      if (!sub_buffer.empty()) {
 
  551    else if (host_view.empty() &&
 
  560      } 
else if (has_dash_dot()) {
 
  561        add_authority_slashes_if_needed();
 
  567    bool succeeded = parse_host(host_view);
 
  569      update_base_hostname(previous_host);
 
  570      update_base_port(previous_port);
 
  571    } 
else if (has_dash_dot()) {
 
  578  size_t location = new_host.find_first_of(
"/\\?");
 
  579  if (location != std::string_view::npos) {
 
  580    new_host.remove_suffix(new_host.length() - location);
 
  583  if (new_host.empty()) {
 
  588    if (!parse_host(new_host)) {
 
  589      update_base_hostname(previous_host);
 
  590      update_base_port(previous_port);
 
  595    if (helpers::substring(buffer, components.host_start,
 
  596                           components.host_end) == 
"localhost") {
 
  605  ada_log(
"url_aggregator::set_host '", input, 
"'");
 
  608  return set_host_or_hostname<false>(input);
 
 
  612  ada_log(
"url_aggregator::set_hostname '", input, 
"'");
 
  615  return set_host_or_hostname<true>(input);
 
 
  619  ada_log(
"url_aggregator::get_origin");
 
  636        return helpers::concat(out->get_protocol(), 
"//", out->get_host());
 
 
  647  ada_log(
"url_aggregator::get_username");
 
  649    return helpers::substring(buffer, components.protocol_end + 2,
 
  650                              components.username_end);
 
 
  657  ada_log(
"url_aggregator::get_password");
 
  659    return helpers::substring(buffer, components.username_end + 1,
 
  660                              components.host_start);
 
 
  667  ada_log(
"url_aggregator::get_port");
 
  671  return helpers::substring(buffer, components.host_end + 1,
 
  672                            components.pathname_start);
 
 
  677  ada_log(
"url_aggregator::get_hash");
 
  683  if (buffer.size() - components.hash_start <= 1) {
 
  686  return helpers::substring(buffer, components.hash_start);
 
 
  691  ada_log(
"url_aggregator::get_host");
 
  695  size_t start = components.host_start;
 
  696  if (components.host_end > components.host_start &&
 
  697      buffer[components.host_start] == 
'@') {
 
  702  if (start == components.host_end) {
 
  705  return helpers::substring(buffer, start, components.pathname_start);
 
 
  710  ada_log(
"url_aggregator::get_hostname");
 
  714  size_t start = components.host_start;
 
  716  if (components.host_end > components.host_start &&
 
  717      buffer[components.host_start] == 
'@') {
 
  720  return helpers::substring(buffer, start, components.host_end);
 
 
  725  ada_log(
"url_aggregator::get_search");
 
  731  auto ending_index = uint32_t(buffer.size());
 
  733    ending_index = components.hash_start;
 
  735  if (ending_index - components.search_start <= 1) {
 
  738  return helpers::substring(buffer, components.search_start, ending_index);
 
 
  743  ada_log(
"url_aggregator::get_protocol");
 
  744  return helpers::substring(buffer, 0, components.protocol_end);
 
 
  748  ada_log(
"url_aggregator::to_string buffer:", buffer, 
" [", buffer.size(),
 
  755  auto back = std::back_insert_iterator(answer);
 
  756  answer.append(
"{\n");
 
  758  answer.append(
"\t\"buffer\":\"");
 
  759  helpers::encode_json(buffer, back);
 
  760  answer.append(
"\",\n");
 
  762  answer.append(
"\t\"protocol\":\"");
 
  764  answer.append(
"\",\n");
 
  767    answer.append(
"\t\"username\":\"");
 
  769    answer.append(
"\",\n");
 
  770    answer.append(
"\t\"password\":\"");
 
  772    answer.append(
"\",\n");
 
  775  answer.append(
"\t\"host\":\"");
 
  776  helpers::encode_json(
get_host(), back);
 
  777  answer.append(
"\",\n");
 
  779  answer.append(
"\t\"path\":\"");
 
  781  answer.append(
"\",\n");
 
  782  answer.append(
"\t\"opaque path\":");
 
  784  answer.append(
",\n");
 
  787    answer.append(
"\t\"query\":\"");
 
  789    answer.append(
"\",\n");
 
  792    answer.append(
"\t\"fragment\":\"");
 
  793    helpers::encode_json(
get_hash(), back);
 
  794    answer.append(
"\",\n");
 
  797  auto convert_offset_to_string = [](uint32_t offset) -> std::string {
 
  801      return std::to_string(offset);
 
  805  answer.append(
"\t\"protocol_end\":");
 
  806  answer.append(convert_offset_to_string(components.protocol_end));
 
  807  answer.append(
",\n");
 
  809  answer.append(
"\t\"username_end\":");
 
  810  answer.append(convert_offset_to_string(components.username_end));
 
  811  answer.append(
",\n");
 
  813  answer.append(
"\t\"host_start\":");
 
  814  answer.append(convert_offset_to_string(components.host_start));
 
  815  answer.append(
",\n");
 
  817  answer.append(
"\t\"host_end\":");
 
  818  answer.append(convert_offset_to_string(components.host_end));
 
  819  answer.append(
",\n");
 
  821  answer.append(
"\t\"port\":");
 
  822  answer.append(convert_offset_to_string(components.port));
 
  823  answer.append(
",\n");
 
  825  answer.append(
"\t\"pathname_start\":");
 
  826  answer.append(convert_offset_to_string(components.pathname_start));
 
  827  answer.append(
",\n");
 
  829  answer.append(
"\t\"search_start\":");
 
  830  answer.append(convert_offset_to_string(components.search_start));
 
  831  answer.append(
",\n");
 
  833  answer.append(
"\t\"hash_start\":");
 
  834  answer.append(convert_offset_to_string(components.hash_start));
 
  835  answer.append(
"\n}");
 
 
  841  if (components.host_start == components.host_end) {
 
 
  847bool url_aggregator::parse_ipv4(std::string_view input, 
bool in_place) {
 
  848  ada_log(
"parse_ipv4 ", input, 
" [", input.size(),
 
  849          " bytes], overlaps with buffer: ",
 
  850          helpers::overlaps(input, buffer) ? 
"yes" : 
"no");
 
  852  const bool trailing_dot = (input.back() == 
'.');
 
  854    input.remove_suffix(1);
 
  856  size_t digit_count{0};
 
  857  int pure_decimal_count = 0;  
 
  860  for (; (digit_count < 4) && !(input.empty()); digit_count++) {
 
  864    if (is_hex && ((input.length() == 2) ||
 
  865                   ((input.length() > 2) && (input[2] == 
'.')))) {
 
  868      input.remove_prefix(2);
 
  870      std::from_chars_result r{};
 
  872        ada_log(
"parse_ipv4 trying to parse hex number");
 
  873        r = std::from_chars(input.data() + 2, input.data() + input.size(),
 
  875      } 
else if ((input.length() >= 2) && input[0] == 
'0' &&
 
  877        ada_log(
"parse_ipv4 trying to parse octal number");
 
  878        r = std::from_chars(input.data() + 1, input.data() + input.size(),
 
  881        ada_log(
"parse_ipv4 trying to parse decimal number");
 
  882        pure_decimal_count++;
 
  883        r = std::from_chars(input.data(), input.data() + input.size(),
 
  886      if (r.ec != std::errc()) {
 
  887        ada_log(
"parse_ipv4 parsing failed");
 
  890      ada_log(
"parse_ipv4 parsed ", segment_result);
 
  891      input.remove_prefix(r.ptr - input.data());
 
  897      if (segment_result >= (uint64_t(1) << (32 - digit_count * 8))) {
 
  900      ipv4 <<= (32 - digit_count * 8);
 
  901      ipv4 |= segment_result;
 
  906      if ((segment_result > 255) || (input[0] != 
'.')) {
 
  910      ipv4 |= segment_result;
 
  911      input.remove_prefix(1);  
 
  914  if ((digit_count != 4) || (!input.empty())) {
 
  915    ada_log(
"parse_ipv4 found invalid (more than 4 numbers or empty) ");
 
  919  ada_log(
"url_aggregator::parse_ipv4 completed ", 
get_href(),
 
  923  if (in_place && pure_decimal_count == 4 && !trailing_dot) {
 
  925        "url_aggregator::parse_ipv4 completed and was already correct in the " 
  930    ada_log(
"url_aggregator::parse_ipv4 completed and we need to update it");
 
  935    update_base_hostname(
 
  943bool url_aggregator::parse_ipv6(std::string_view input) {
 
  948  ada_log(
"parse_ipv6 ", input, 
" [", input.size(), 
" bytes]");
 
  955  std::array<uint16_t, 8> address{};
 
  961  std::optional<int> compress{};
 
  964  std::string_view::iterator pointer = input.begin();
 
  967  if (input[0] == 
':') {
 
  970    if (input.size() == 1 || input[1] != 
':') {
 
  971      ada_log(
"parse_ipv6 starts with : but the rest does not start with :");
 
  979    compress = ++piece_index;
 
  983  while (pointer != input.end()) {
 
  985    if (piece_index == 8) {
 
  986      ada_log(
"parse_ipv6 piece_index == 8");
 
  991    if (*pointer == 
':') {
 
  993      if (compress.has_value()) {
 
  994        ada_log(
"parse_ipv6 compress is non-null");
 
 1001      compress = ++piece_index;
 
 1006    uint16_t value = 0, length = 0;
 
 1011    while (length < 4 && pointer != input.end() &&
 
 1012           unicode::is_ascii_hex_digit(*pointer)) {
 
 1014      value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
 
 1020    if (pointer != input.end() && *pointer == 
'.') {
 
 1023        ada_log(
"parse_ipv6 length is 0");
 
 1031      if (piece_index > 6) {
 
 1032        ada_log(
"parse_ipv6 piece_index > 6");
 
 1037      int numbers_seen = 0;
 
 1040      while (pointer != input.end()) {
 
 1042        std::optional<uint16_t> ipv4_piece{};
 
 1045        if (numbers_seen > 0) {
 
 1048          if (*pointer == 
'.' && numbers_seen < 4) {
 
 1052            ada_log(
"parse_ipv6 Otherwise, validation error, return failure");
 
 1060              "parse_ipv6 If c is not an ASCII digit, validation error, return " 
 1068          int number = *pointer - 
'0';
 
 1071          if (!ipv4_piece.has_value()) {
 
 1072            ipv4_piece = number;
 
 1075          else if (ipv4_piece == 0) {
 
 1076            ada_log(
"parse_ipv6 if ipv4Piece is 0, validation error");
 
 1081            ipv4_piece = *ipv4_piece * 10 + number;
 
 1085          if (ipv4_piece > 255) {
 
 1086            ada_log(
"parse_ipv6 ipv4_piece > 255");
 
 1097        address[piece_index] =
 
 1098            uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
 
 1104        if (numbers_seen == 2 || numbers_seen == 4) {
 
 1110      if (numbers_seen != 4) {
 
 1118    else if ((pointer != input.end()) && (*pointer == 
':')) {
 
 1123      if (pointer == input.end()) {
 
 1125            "parse_ipv6 If c is the EOF code point, validation error, return " 
 1132    else if (pointer != input.end()) {
 
 1134          "parse_ipv6 Otherwise, if c is not the EOF code point, validation " 
 1135          "error, return failure");
 
 1140    address[piece_index] = value;
 
 1147  if (compress.has_value()) {
 
 1149    int swaps = piece_index - *compress;
 
 1157    while (piece_index != 0 && swaps > 0) {
 
 1158      std::swap(address[piece_index], address[*compress + swaps - 1]);
 
 1165  else if (piece_index != 8) {
 
 1167        "parse_ipv6 if compress is null and pieceIndex is not 8, validation " 
 1168        "error, return failure");
 
 1181bool url_aggregator::parse_opaque_host(std::string_view input) {
 
 1182  ada_log(
"parse_opaque_host ", input, 
" [", input.size(), 
" bytes]");
 
 1185  if (std::any_of(input.begin(), input.end(),
 
 1186                  ada::unicode::is_forbidden_host_code_point)) {
 
 1194  if (idx == input.size()) {
 
 1195    update_base_hostname(input);
 
 1198    update_base_hostname(ada::unicode::percent_encode(
 
 1210  answer.append(buffer);
 
 1211  answer.append(
" [");
 
 1212  answer.append(std::to_string(buffer.size()));
 
 1213  answer.append(
" bytes]");
 
 1214  answer.append(
"\n");
 
 1217  line1.resize(buffer.size(), 
' ');
 
 1219    line1[components.hash_start] = 
'|';
 
 1222    line1[components.search_start] = 
'|';
 
 1224  if (components.pathname_start != buffer.size()) {
 
 1225    line1[components.pathname_start] = 
'|';
 
 1227  if (components.host_end != buffer.size()) {
 
 1228    line1[components.host_end] = 
'|';
 
 1230  if (components.host_start != buffer.size()) {
 
 1231    line1[components.host_start] = 
'|';
 
 1233  if (components.username_end != buffer.size()) {
 
 1234    line1[components.username_end] = 
'|';
 
 1236  if (components.protocol_end != buffer.size()) {
 
 1237    line1[components.protocol_end] = 
'|';
 
 1239  answer.append(line1);
 
 1240  answer.append(
"\n");
 
 1242  std::string line2 = line1;
 
 1244    line2[components.hash_start] = 
'`';
 
 1245    line1[components.hash_start] = 
' ';
 
 1247    for (
size_t i = components.hash_start + 1; i < line2.size(); i++) {
 
 1250    line2.append(
" hash_start");
 
 1251    answer.append(line2);
 
 1252    answer.append(
"\n");
 
 1255  std::string line3 = line1;
 
 1257    line3[components.search_start] = 
'`';
 
 1258    line1[components.search_start] = 
' ';
 
 1260    for (
size_t i = components.search_start + 1; i < line3.size(); i++) {
 
 1263    line3.append(
" search_start ");
 
 1264    line3.append(std::to_string(components.search_start));
 
 1265    answer.append(line3);
 
 1266    answer.append(
"\n");
 
 1269  std::string line4 = line1;
 
 1270  if (components.pathname_start != buffer.size()) {
 
 1271    line4[components.pathname_start] = 
'`';
 
 1272    line1[components.pathname_start] = 
' ';
 
 1273    for (
size_t i = components.pathname_start + 1; i < line4.size(); i++) {
 
 1276    line4.append(
" pathname_start ");
 
 1277    line4.append(std::to_string(components.pathname_start));
 
 1278    answer.append(line4);
 
 1279    answer.append(
"\n");
 
 1282  std::string line5 = line1;
 
 1283  if (components.host_end != buffer.size()) {
 
 1284    line5[components.host_end] = 
'`';
 
 1285    line1[components.host_end] = 
' ';
 
 1287    for (
size_t i = components.host_end + 1; i < line5.size(); i++) {
 
 1290    line5.append(
" host_end ");
 
 1291    line5.append(std::to_string(components.host_end));
 
 1292    answer.append(line5);
 
 1293    answer.append(
"\n");
 
 1296  std::string line6 = line1;
 
 1297  if (components.host_start != buffer.size()) {
 
 1298    line6[components.host_start] = 
'`';
 
 1299    line1[components.host_start] = 
' ';
 
 1301    for (
size_t i = components.host_start + 1; i < line6.size(); i++) {
 
 1304    line6.append(
" host_start ");
 
 1305    line6.append(std::to_string(components.host_start));
 
 1306    answer.append(line6);
 
 1307    answer.append(
"\n");
 
 1310  std::string line7 = line1;
 
 1311  if (components.username_end != buffer.size()) {
 
 1312    line7[components.username_end] = 
'`';
 
 1313    line1[components.username_end] = 
' ';
 
 1315    for (
size_t i = components.username_end + 1; i < line7.size(); i++) {
 
 1318    line7.append(
" username_end ");
 
 1319    line7.append(std::to_string(components.username_end));
 
 1320    answer.append(line7);
 
 1321    answer.append(
"\n");
 
 1324  std::string line8 = line1;
 
 1325  if (components.protocol_end != buffer.size()) {
 
 1326    line8[components.protocol_end] = 
'`';
 
 1327    line1[components.protocol_end] = 
' ';
 
 1329    for (
size_t i = components.protocol_end + 1; i < line8.size(); i++) {
 
 1332    line8.append(
" protocol_end ");
 
 1333    line8.append(std::to_string(components.protocol_end));
 
 1334    answer.append(line8);
 
 1335    answer.append(
"\n");
 
 1339    answer.append(
"note: hash omitted\n");
 
 1342    answer.append(
"note: search omitted\n");
 
 1344  if (components.protocol_end > buffer.size()) {
 
 1345    answer.append(
"warning: protocol_end overflows\n");
 
 1347  if (components.username_end > buffer.size()) {
 
 1348    answer.append(
"warning: username_end overflows\n");
 
 1350  if (components.host_start > buffer.size()) {
 
 1351    answer.append(
"warning: host_start overflows\n");
 
 1353  if (components.host_end > buffer.size()) {
 
 1354    answer.append(
"warning: host_end overflows\n");
 
 1356  if (components.pathname_start > buffer.size()) {
 
 1357    answer.append(
"warning: pathname_start overflows\n");
 
 
 1362void url_aggregator::delete_dash_dot() {
 
 1363  ada_log(
"url_aggregator::delete_dash_dot");
 
 1366  buffer.erase(components.
host_end, 2);
 
 1378inline void url_aggregator::consume_prepared_path(std::string_view input) {
 
 1379  ada_log(
"url_aggregator::consume_prepared_path ", input);
 
 1389  uint8_t accumulator = checkers::path_signature(input);
 
 1394  constexpr uint8_t need_encoding = 1;
 
 1395  constexpr uint8_t backslash_char = 2;
 
 1396  constexpr uint8_t dot_char = 4;
 
 1397  constexpr uint8_t percent_char = 8;
 
 1402      (special ? (accumulator == 0)
 
 1403               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
 
 1405      (!may_need_slow_file_handling);
 
 1406  if (accumulator == dot_char && !may_need_slow_file_handling) {
 
 1414    if (input[0] != 
'.') {
 
 1415      size_t slashdot = input.find(
"/.");
 
 1416      if (slashdot == std::string_view::npos) {  
 
 1417        trivial_path = 
true;
 
 1421            !(slashdot + 2 == input.size() || input[slashdot + 2] == 
'.' ||
 
 1422              input[slashdot + 2] == 
'/');
 
 1426  if (trivial_path && is_at_path()) {
 
 1427    ada_log(
"parse_path trivial");
 
 1439       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
 
 1442    ada_log(
"parse_prepared_path fast");
 
 1447    size_t previous_location = 0;  
 
 1449      size_t new_location = input.find(
'/', previous_location);
 
 1452      if (new_location == std::string_view::npos) {
 
 1453        std::string_view path_view = input.substr(previous_location);
 
 1454        if (path_view == 
"..") {  
 
 1458            update_base_pathname(path);
 
 1462          if (path.back() == 
'/') {
 
 1463            update_base_pathname(path);
 
 1468          path.resize(path.rfind(
'/') + 1);
 
 1469          update_base_pathname(path);
 
 1473        if (path_view != 
".") {
 
 1474          path.append(path_view);
 
 1476        update_base_pathname(path);
 
 1480        std::string_view path_view =
 
 1481            input.substr(previous_location, new_location - previous_location);
 
 1482        previous_location = new_location + 1;
 
 1483        if (path_view == 
"..") {
 
 1484          size_t last_delimiter = path.rfind(
'/');
 
 1485          if (last_delimiter != std::string::npos) {
 
 1486            path.erase(last_delimiter);
 
 1488        } 
else if (path_view != 
".") {
 
 1490          path.append(path_view);
 
 1495    ada_log(
"parse_path slow");
 
 1497    bool needs_percent_encoding = (accumulator & 1);
 
 1498    std::string path_buffer_tmp;
 
 1500      size_t location = (special && (accumulator & 2))
 
 1501                            ? input.find_first_of(
"/\\")
 
 1503      std::string_view path_view = input;
 
 1504      if (location != std::string_view::npos) {
 
 1505        path_view.remove_suffix(path_view.size() - location);
 
 1506        input.remove_prefix(location + 1);
 
 1510      std::string_view path_buffer =
 
 1511          (needs_percent_encoding &&
 
 1512           ada::unicode::percent_encode<false>(
 
 1516      if (unicode::is_double_dot_path_segment(path_buffer)) {
 
 1517        if ((helpers::shorten_path(path, type) || special) &&
 
 1518            location == std::string_view::npos) {
 
 1521      } 
else if (unicode::is_single_dot_path_segment(path_buffer) &&
 
 1522                 (location == std::string_view::npos)) {
 
 1526      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
 
 1533          path += path_buffer[0];
 
 1535          path_buffer.remove_prefix(2);
 
 1536          path.append(path_buffer);
 
 1540          path.append(path_buffer);
 
 1543      if (location == std::string_view::npos) {
 
 1544        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.
 
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
 
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.
 
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 basic URL definitions.
 
Declaration for the URL Components.