11bool url::parse_opaque_host(std::string_view input) {
12 ada_log(
"parse_opaque_host ", input,
" [", input.size(),
" bytes]");
13 if (std::any_of(input.begin(), input.end(),
14 ada::unicode::is_forbidden_host_code_point)) {
20 host = ada::unicode::percent_encode(
25bool url::parse_ipv4(std::string_view input) {
26 ada_log(
"parse_ipv4 ", input,
" [", input.size(),
" bytes]");
27 if (input.back() ==
'.') {
28 input.remove_suffix(1);
30 size_t digit_count{0};
31 int pure_decimal_count = 0;
32 std::string_view original_input =
36 for (; (digit_count < 4) && !(input.empty()); digit_count++) {
40 if (is_hex && ((input.length() == 2) ||
41 ((input.length() > 2) && (input[2] ==
'.')))) {
44 input.remove_prefix(2);
46 std::from_chars_result r{};
48 r = std::from_chars(input.data() + 2, input.data() + input.size(),
50 }
else if ((input.length() >= 2) && input[0] ==
'0' &&
52 r = std::from_chars(input.data() + 1, input.data() + input.size(),
56 r = std::from_chars(input.data(), input.data() + input.size(),
59 if (r.ec != std::errc()) {
62 input.remove_prefix(r.ptr - input.data());
68 if (segment_result >= (uint64_t(1) << (32 - digit_count * 8))) {
71 ipv4 <<= (32 - digit_count * 8);
72 ipv4 |= segment_result;
77 if ((segment_result > 255) || (input[0] !=
'.')) {
81 ipv4 |= segment_result;
82 input.remove_prefix(1);
85 if ((digit_count != 4) || (!input.empty())) {
90 if (pure_decimal_count == 4) {
91 host = original_input;
100bool url::parse_ipv6(std::string_view input) {
101 ada_log(
"parse_ipv6 ", input,
" [", input.size(),
" bytes]");
107 std::array<uint16_t, 8> address{};
113 std::optional<int> compress{};
116 std::string_view::iterator pointer = input.begin();
119 if (input[0] ==
':') {
122 if (input.size() == 1 || input[1] !=
':') {
123 ada_log(
"parse_ipv6 starts with : but the rest does not start with :");
131 compress = ++piece_index;
135 while (pointer != input.end()) {
137 if (piece_index == 8) {
138 ada_log(
"parse_ipv6 piece_index == 8");
143 if (*pointer ==
':') {
145 if (compress.has_value()) {
146 ada_log(
"parse_ipv6 compress is non-null");
153 compress = ++piece_index;
158 uint16_t value = 0, length = 0;
163 while (length < 4 && pointer != input.end() &&
164 unicode::is_ascii_hex_digit(*pointer)) {
166 value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
172 if (pointer != input.end() && *pointer ==
'.') {
175 ada_log(
"parse_ipv6 length is 0");
183 if (piece_index > 6) {
184 ada_log(
"parse_ipv6 piece_index > 6");
189 int numbers_seen = 0;
192 while (pointer != input.end()) {
194 std::optional<uint16_t> ipv4_piece{};
197 if (numbers_seen > 0) {
200 if (*pointer ==
'.' && numbers_seen < 4) {
205 ada_log(
"parse_ipv6 Otherwise, validation error, return failure");
213 "parse_ipv6 If c is not an ASCII digit, validation error, return "
221 int number = *pointer -
'0';
224 if (!ipv4_piece.has_value()) {
228 else if (ipv4_piece == 0) {
229 ada_log(
"parse_ipv6 if ipv4Piece is 0, validation error");
234 ipv4_piece = *ipv4_piece * 10 + number;
238 if (ipv4_piece > 255) {
239 ada_log(
"parse_ipv6 ipv4_piece > 255");
250 address[piece_index] =
251 uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
257 if (numbers_seen == 2 || numbers_seen == 4) {
263 if (numbers_seen != 4) {
271 else if ((pointer != input.end()) && (*pointer ==
':')) {
276 if (pointer == input.end()) {
278 "parse_ipv6 If c is the EOF code point, validation error, return "
285 else if (pointer != input.end()) {
287 "parse_ipv6 Otherwise, if c is not the EOF code point, validation "
288 "error, return failure");
293 address[piece_index] = value;
300 if (compress.has_value()) {
302 int swaps = piece_index - *compress;
310 while (piece_index != 0 && swaps > 0) {
311 std::swap(address[piece_index], address[*compress + swaps - 1]);
318 else if (piece_index != 8) {
320 "parse_ipv6 if compress is null and pieceIndex is not 8, validation "
321 "error, return failure");
325 ada_log(
"parse_ipv6 ", *host);
330template <
bool has_state_overr
ide>
338 if (is_input_special) {
339 if (has_state_override) {
356 host.value().empty()) {
363 if (has_state_override) {
367 if (urls_scheme_port) {
370 if (port.has_value() && *port == urls_scheme_port) {
376 std::string _buffer(input);
381 unicode::to_lower_ascii(_buffer.data(), _buffer.size());
383 if (has_state_override) {
387 if (
is_special() != ada::scheme::is_special(_buffer)) {
400 host.value().empty()) {
405 set_scheme(std::move(_buffer));
407 if (has_state_override) {
411 if (urls_scheme_port) {
414 if (port.has_value() && *port == urls_scheme_port) {
425 ada_log(
"parse_host ", input,
" [", input.size(),
" bytes]");
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);
454 std::string buffer = std::string(input);
458 unicode::to_lower_ascii(buffer.data(), buffer.size());
459 bool is_forbidden = unicode::contains_forbidden_domain_code_point(
460 buffer.data(), buffer.size());
461 if (is_forbidden == 0 && buffer.find(
"xn-") == std::string_view::npos) {
463 host = std::move(buffer);
464 if (checkers::is_ipv4(host.value())) {
465 ada_log(
"parse_host fast path ipv4");
466 return parse_ipv4(host.value());
468 ada_log(
"parse_host fast path ", *host);
471 ada_log(
"parse_host calling to_ascii");
472 is_valid = ada::unicode::to_ascii(host, input, input.find(
'%'));
474 ada_log(
"parse_host to_ascii returns false");
477 ada_log(
"parse_host to_ascii succeeded ", *host,
" [", host->size(),
480 if (std::any_of(host.value().begin(), host.value().end(),
481 ada::unicode::is_forbidden_domain_code_point)) {
488 if (checkers::is_ipv4(host.value())) {
489 ada_log(
"parse_host got ipv4 ", *host);
490 return parse_ipv4(host.value());
497 ada_log(
"parse_path ", input);
498 std::string tmp_buffer;
499 std::string_view internal_input;
500 if (unicode::has_tabs_or_newline(input)) {
504 helpers::remove_ascii_tab_or_newline(tmp_buffer);
505 internal_input = tmp_buffer;
507 internal_input = input;
512 if (internal_input.empty()) {
514 }
else if ((internal_input[0] ==
'/') || (internal_input[0] ==
'\\')) {
515 helpers::parse_prepared_path(internal_input.substr(1), type, path);
518 helpers::parse_prepared_path(internal_input, type, path);
521 }
else if (!internal_input.empty()) {
522 if (internal_input[0] ==
'/') {
523 helpers::parse_prepared_path(internal_input.substr(1), type, path);
526 helpers::parse_prepared_path(internal_input, type, path);
530 if (!host.has_value()) {
541 auto back = std::back_insert_iterator(answer);
542 answer.append(
"{\n");
543 answer.append(
"\t\"protocol\":\"");
545 answer.append(
"\",\n");
547 answer.append(
"\t\"username\":\"");
548 helpers::encode_json(username, back);
549 answer.append(
"\",\n");
550 answer.append(
"\t\"password\":\"");
551 helpers::encode_json(password, back);
552 answer.append(
"\",\n");
554 if (host.has_value()) {
555 answer.append(
"\t\"host\":\"");
556 helpers::encode_json(host.value(), back);
557 answer.append(
"\",\n");
559 if (port.has_value()) {
560 answer.append(
"\t\"port\":\"");
561 answer.append(std::to_string(port.value()));
562 answer.append(
"\",\n");
564 answer.append(
"\t\"path\":\"");
565 helpers::encode_json(path, back);
566 answer.append(
"\",\n");
567 answer.append(
"\t\"opaque path\":");
570 answer.append(
",\n");
571 answer.append(
"\t\"query\":\"");
572 helpers::encode_json(query.value(), back);
575 if (hash.has_value()) {
576 answer.append(
",\n");
577 answer.append(
"\t\"hash\":\"");
578 helpers::encode_json(hash.value(), back);
581 answer.append(
"\n}");
586 if (!host.has_value()) {
589 return checkers::verify_dns_length(host.value());
Includes all definitions for Ada.
#define ada_really_inline
constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32]
bool has_hex_prefix(std::string_view input)
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
Declarations for the URL scheme.
ada_really_inline bool is_special() const noexcept
ada_really_inline bool has_credentials() const noexcept
std::string to_string() const override
std::string get_protocol() const noexcept
bool has_valid_domain() const noexcept override
bool has_search() const noexcept override