12bool url::parse_opaque_host(std::string_view input) {
 
   13  ada_log(
"parse_opaque_host ", input, 
" [", input.size(), 
" bytes]");
 
   14  if (std::ranges::any_of(input.begin(), input.end(),
 
   15                          ada::unicode::is_forbidden_host_code_point)) {
 
   21  host = ada::unicode::percent_encode(
 
   26bool url::parse_ipv4(std::string_view input) {
 
   27  ada_log(
"parse_ipv4 ", input, 
" [", input.size(), 
" bytes]");
 
   28  if (input.back() == 
'.') {
 
   29    input.remove_suffix(1);
 
   31  size_t digit_count{0};
 
   32  int pure_decimal_count = 0;  
 
   33  std::string_view original_input =
 
   37  for (; (digit_count < 4) && !(input.empty()); digit_count++) {
 
   41    if (is_hex && ((input.length() == 2) ||
 
   42                   ((input.length() > 2) && (input[2] == 
'.')))) {
 
   45      input.remove_prefix(2);
 
   47      std::from_chars_result r{};
 
   49        r = std::from_chars(input.data() + 2, input.data() + input.size(),
 
   51      } 
else if ((input.length() >= 2) && input[0] == 
'0' &&
 
   53        r = std::from_chars(input.data() + 1, input.data() + input.size(),
 
   57        r = std::from_chars(input.data(), input.data() + input.size(),
 
   60      if (r.ec != std::errc()) {
 
   63      input.remove_prefix(r.ptr - input.data());
 
   69      if (segment_result >= (uint64_t(1) << (32 - digit_count * 8))) {
 
   72      ipv4 <<= (32 - digit_count * 8);
 
   73      ipv4 |= segment_result;
 
   78      if ((segment_result > 255) || (input[0] != 
'.')) {
 
   82      ipv4 |= segment_result;
 
   83      input.remove_prefix(1);  
 
   86  if ((digit_count != 4) || (!input.empty())) {
 
   91  if (pure_decimal_count == 4) {
 
   92    host = original_input;  
 
  101bool url::parse_ipv6(std::string_view input) {
 
  102  ada_log(
"parse_ipv6 ", input, 
" [", input.size(), 
" bytes]");
 
  108  std::array<uint16_t, 8> address{};
 
  114  std::optional<int> compress{};
 
  117  std::string_view::iterator pointer = input.begin();
 
  120  if (input[0] == 
':') {
 
  123    if (input.size() == 1 || input[1] != 
':') {
 
  124      ada_log(
"parse_ipv6 starts with : but the rest does not start with :");
 
  132    compress = ++piece_index;
 
  136  while (pointer != input.end()) {
 
  138    if (piece_index == 8) {
 
  139      ada_log(
"parse_ipv6 piece_index == 8");
 
  144    if (*pointer == 
':') {
 
  146      if (compress.has_value()) {
 
  147        ada_log(
"parse_ipv6 compress is non-null");
 
  154      compress = ++piece_index;
 
  159    uint16_t value = 0, length = 0;
 
  164    while (length < 4 && pointer != input.end() &&
 
  165           unicode::is_ascii_hex_digit(*pointer)) {
 
  167      value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
 
  173    if (pointer != input.end() && *pointer == 
'.') {
 
  176        ada_log(
"parse_ipv6 length is 0");
 
  184      if (piece_index > 6) {
 
  185        ada_log(
"parse_ipv6 piece_index > 6");
 
  190      int numbers_seen = 0;
 
  193      while (pointer != input.end()) {
 
  195        std::optional<uint16_t> ipv4_piece{};
 
  198        if (numbers_seen > 0) {
 
  201          if (*pointer == 
'.' && numbers_seen < 4) {
 
  206            ada_log(
"parse_ipv6 Otherwise, validation error, return failure");
 
  214              "parse_ipv6 If c is not an ASCII digit, validation error, return " 
  222          int number = *pointer - 
'0';
 
  225          if (!ipv4_piece.has_value()) {
 
  229          else if (ipv4_piece == 0) {
 
  230            ada_log(
"parse_ipv6 if ipv4Piece is 0, validation error");
 
  235            ipv4_piece = *ipv4_piece * 10 + number;
 
  239          if (ipv4_piece > 255) {
 
  240            ada_log(
"parse_ipv6 ipv4_piece > 255");
 
  251        address[piece_index] =
 
  252            uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
 
  258        if (numbers_seen == 2 || numbers_seen == 4) {
 
  264      if (numbers_seen != 4) {
 
  272    else if ((pointer != input.end()) && (*pointer == 
':')) {
 
  277      if (pointer == input.end()) {
 
  279            "parse_ipv6 If c is the EOF code point, validation error, return " 
  286    else if (pointer != input.end()) {
 
  288          "parse_ipv6 Otherwise, if c is not the EOF code point, validation " 
  289          "error, return failure");
 
  294    address[piece_index] = value;
 
  301  if (compress.has_value()) {
 
  303    int swaps = piece_index - *compress;
 
  311    while (piece_index != 0 && swaps > 0) {
 
  312      std::swap(address[piece_index], address[*compress + swaps - 1]);
 
  319  else if (piece_index != 8) {
 
  321        "parse_ipv6 if compress is null and pieceIndex is not 8, validation " 
  322        "error, return failure");
 
  326  ada_log(
"parse_ipv6 ", *host);
 
  331template <
bool has_state_overr
ide>
 
  339  if (is_input_special) {  
 
  340    if constexpr (has_state_override) {
 
  357          host.value().empty()) {
 
  364    if constexpr (has_state_override) {
 
  366      uint16_t urls_scheme_port = get_special_port();
 
  368      if (urls_scheme_port) {
 
  371        if (port.has_value() && *port == urls_scheme_port) {
 
  377    std::string _buffer(input);
 
  382    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
 
  384    if constexpr (has_state_override) {
 
  388      if (
is_special() != ada::scheme::is_special(_buffer)) {
 
  401          host.value().empty()) {
 
  406    set_scheme(std::move(_buffer));
 
  408    if constexpr (has_state_override) {
 
  410      uint16_t urls_scheme_port = get_special_port();
 
  412      if (urls_scheme_port) {
 
  415        if (port.has_value() && *port == urls_scheme_port) {
 
  426  ada_log(
"parse_host ", input, 
" [", input.size(), 
" bytes]");
 
  431  if (input[0] == 
'[') {
 
  433    if (input.back() != 
']') {
 
  436    ada_log(
"parse_host ipv6");
 
  440    input.remove_prefix(1);
 
  441    input.remove_suffix(1);
 
  442    return parse_ipv6(input);
 
  448    return parse_opaque_host(input);
 
  455  std::string buffer = std::string(input);
 
  459  unicode::to_lower_ascii(buffer.data(), buffer.size());
 
  460  bool is_forbidden = unicode::contains_forbidden_domain_code_point(
 
  461      buffer.data(), buffer.size());
 
  462  if (is_forbidden == 0 && buffer.find(
"xn-") == std::string_view::npos) {
 
  464    host = std::move(buffer);
 
  465    if (checkers::is_ipv4(host.value())) {
 
  466      ada_log(
"parse_host fast path ipv4");
 
  467      return parse_ipv4(host.value());
 
  469    ada_log(
"parse_host fast path ", *host);
 
  472  ada_log(
"parse_host calling to_ascii");
 
  473  is_valid = ada::unicode::to_ascii(host, input, input.find(
'%'));
 
  475    ada_log(
"parse_host to_ascii returns false");
 
  478  ada_log(
"parse_host to_ascii succeeded ", *host, 
" [", host->size(),
 
  481  if (std::any_of(host.value().begin(), host.value().end(),
 
  482                  ada::unicode::is_forbidden_domain_code_point)) {
 
  489  if (checkers::is_ipv4(host.value())) {
 
  490    ada_log(
"parse_host got ipv4 ", *host);
 
  491    return parse_ipv4(host.value());
 
  498  ada_log(
"parse_path ", input);
 
  499  std::string tmp_buffer;
 
  500  std::string_view internal_input;
 
  501  if (unicode::has_tabs_or_newline(input)) {
 
  505    helpers::remove_ascii_tab_or_newline(tmp_buffer);
 
  506    internal_input = tmp_buffer;
 
  508    internal_input = input;
 
  513    if (internal_input.empty()) {
 
  515    } 
else if ((internal_input[0] == 
'/') || (internal_input[0] == 
'\\')) {
 
  516      helpers::parse_prepared_path(internal_input.substr(1), type, path);
 
  518      helpers::parse_prepared_path(internal_input, type, path);
 
  520  } 
else if (!internal_input.empty()) {
 
  521    if (internal_input[0] == 
'/') {
 
  522      helpers::parse_prepared_path(internal_input.substr(1), type, path);
 
  524      helpers::parse_prepared_path(internal_input, type, path);
 
  527    if (!host.has_value()) {
 
  538  auto back = std::back_insert_iterator(answer);
 
  539  answer.append(
"{\n");
 
  540  answer.append(
"\t\"protocol\":\"");
 
  542  answer.append(
"\",\n");
 
  544    answer.append(
"\t\"username\":\"");
 
  545    helpers::encode_json(username, back);
 
  546    answer.append(
"\",\n");
 
  547    answer.append(
"\t\"password\":\"");
 
  548    helpers::encode_json(password, back);
 
  549    answer.append(
"\",\n");
 
  551  if (host.has_value()) {
 
  552    answer.append(
"\t\"host\":\"");
 
  553    helpers::encode_json(host.value(), back);
 
  554    answer.append(
"\",\n");
 
  556  if (port.has_value()) {
 
  557    answer.append(
"\t\"port\":\"");
 
  558    answer.append(std::to_string(port.value()));
 
  559    answer.append(
"\",\n");
 
  561  answer.append(
"\t\"path\":\"");
 
  562  helpers::encode_json(path, back);
 
  563  answer.append(
"\",\n");
 
  564  answer.append(
"\t\"opaque path\":");
 
  567    answer.append(
",\n");
 
  568    answer.append(
"\t\"query\":\"");
 
  569    helpers::encode_json(query.value(), back);
 
  572  if (hash.has_value()) {
 
  573    answer.append(
",\n");
 
  574    answer.append(
"\t\"hash\":\"");
 
  575    helpers::encode_json(hash.value(), back);
 
  578  answer.append(
"\n}");
 
 
  583  if (!host.has_value()) {
 
  586  return checkers::verify_dns_length(host.value());
 
 
  598  if (non_special_scheme == 
"blob") {
 
  605        return ada::helpers::concat(
result->get_protocol(), 
"//",
 
 
  620  return helpers::concat(non_special_scheme, 
":");
 
 
  628  if (!host.has_value()) {
 
  631  if (port.has_value()) {
 
  632    return host.value() + 
":" + 
get_port();
 
 
  638  return host.value_or(
"");
 
 
  644  return (!query.has_value() || (query.value().empty())) ? 
"" 
  645                                                         : 
"?" + query.value();
 
 
  657  return port.has_value() ? std::to_string(port.value()) : 
"";
 
 
  663  return (!hash.has_value() || (hash.value().empty())) ? 
"" 
  664                                                       : 
"#" + hash.value();
 
 
  667template <
bool overr
ide_hostname>
 
  668bool url::set_host_or_hostname(
const std::string_view input) {
 
  673  std::optional<std::string> previous_host = host;
 
  674  std::optional<uint16_t> previous_port = port;
 
  676  size_t host_end_pos = input.find(
'#');
 
  677  std::string _host(input.data(), host_end_pos != std::string_view::npos
 
  680  helpers::remove_ascii_tab_or_newline(_host);
 
  681  std::string_view new_host(_host);
 
  686    std::string_view host_view(_host.data(), _host.length());
 
  687    auto [location, found_colon] =
 
  688        helpers::get_host_delimiter_location(
is_special(), host_view);
 
  694      if constexpr (override_hostname) {
 
  697      std::string_view buffer = new_host.substr(location + 1);
 
  698      if (!buffer.empty()) {
 
  706    else if (host_view.empty() &&
 
  717    bool succeeded = parse_host(host_view);
 
  719      host = std::move(previous_host);
 
  720      update_base_port(previous_port);
 
  725  size_t location = new_host.find_first_of(
"/\\?");
 
  726  if (location != std::string_view::npos) {
 
  727    new_host.remove_suffix(new_host.length() - location);
 
  730  if (new_host.empty()) {
 
  735    if (!parse_host(new_host)) {
 
  736      host = std::move(previous_host);
 
  737      update_base_port(previous_port);
 
  742    if (host == 
"localhost") {
 
  750  return set_host_or_hostname<false>(input);
 
 
  754  return set_host_or_hostname<true>(input);
 
 
  758  if (cannot_have_credentials_or_port()) {
 
  761  username = ada::unicode::percent_encode(
 
 
  767  if (cannot_have_credentials_or_port()) {
 
  770  password = ada::unicode::percent_encode(
 
 
  776  if (cannot_have_credentials_or_port()) {
 
  779  std::string trimmed(input);
 
  780  helpers::remove_ascii_tab_or_newline(trimmed);
 
  781  if (trimmed.empty()) {
 
  787  if (!ada::unicode::is_ascii_digit(trimmed.front())) {
 
  792  std::optional<uint16_t> previous_port = port;
 
  797  port = std::move(previous_port);
 
 
  805    helpers::strip_trailing_spaces_from_opaque_path(*
this);
 
  809  std::string new_value;
 
  810  new_value = input[0] == 
'#' ? input.substr(1) : input;
 
  811  helpers::remove_ascii_tab_or_newline(new_value);
 
  812  hash = unicode::percent_encode(new_value,
 
 
  818    query = std::nullopt;
 
  819    helpers::strip_trailing_spaces_from_opaque_path(*
this);
 
  823  std::string new_value;
 
  824  new_value = input[0] == 
'?' ? input.substr(1) : input;
 
  825  helpers::remove_ascii_tab_or_newline(new_value);
 
  827  auto query_percent_encode_set =
 
  831  query = ada::unicode::percent_encode(new_value, query_percent_encode_set);
 
 
  844  std::string view(input);
 
  845  helpers::remove_ascii_tab_or_newline(view);
 
  857  std::string::iterator pointer =
 
  858      std::ranges::find_if_not(view, unicode::is_alnum_plus);
 
  860  if (pointer != view.end() && *pointer == 
':') {
 
  861    return parse_scheme<true>(
 
  862        std::string_view(view.data(), pointer - view.begin()));
 
 
  874  return out.has_value();
 
 
#define ada_really_inline
 
constexpr uint8_t QUERY_PERCENT_ENCODE[32]
 
constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32]
 
constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32]
 
constexpr uint8_t USERINFO_PERCENT_ENCODE[32]
 
constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32]
 
constexpr bool has_hex_prefix(std::string_view input)
 
constexpr bool is_alpha(char x) noexcept
 
constexpr bool is_digit(char x) noexcept
 
constexpr std::string_view is_special_list[]
 
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
 
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)
 
Definitions for the URL scheme.
 
ada_really_inline constexpr bool is_special() const noexcept
 
void set_hash(std::string_view input)
 
std::string get_search() const noexcept
 
bool set_hostname(std::string_view input)
 
bool set_host(std::string_view input)
 
ada_really_inline bool has_credentials() const noexcept
 
bool set_password(std::string_view input)
 
void set_search(std::string_view input)
 
bool set_href(std::string_view input)
 
bool set_username(std::string_view input)
 
std::string get_host() const noexcept
 
std::string get_hash() const noexcept
 
bool set_pathname(std::string_view input)
 
std::string get_origin() const noexcept override
 
std::string get_hostname() const noexcept
 
const std::string & get_password() const noexcept
 
bool set_protocol(std::string_view input)
 
std::string get_port() const noexcept
 
const std::string & get_username() const noexcept
 
bool set_port(std::string_view input)
 
constexpr bool has_search() const noexcept override
 
std::string to_string() const override
 
std::string get_protocol() const noexcept
 
bool has_valid_domain() const noexcept override
 
Definitions for unicode operations.