1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "url/url_canon_ip.h" 6 7 #include <stdlib.h> 8 9 #include "base/basictypes.h" 10 #include "base/logging.h" 11 #include "url/url_canon_internal.h" 12 13 namespace url_canon { 14 15 namespace { 16 17 // Converts one of the character types that represent a numerical base to the 18 // corresponding base. 19 int BaseForType(SharedCharTypes type) { 20 switch (type) { 21 case CHAR_HEX: 22 return 16; 23 case CHAR_DEC: 24 return 10; 25 case CHAR_OCT: 26 return 8; 27 default: 28 return 0; 29 } 30 } 31 32 template<typename CHAR, typename UCHAR> 33 bool DoFindIPv4Components(const CHAR* spec, 34 const url_parse::Component& host, 35 url_parse::Component components[4]) { 36 if (!host.is_nonempty()) 37 return false; 38 39 int cur_component = 0; // Index of the component we're working on. 40 int cur_component_begin = host.begin; // Start of the current component. 41 int end = host.end(); 42 for (int i = host.begin; /* nothing */; i++) { 43 if (i >= end || spec[i] == '.') { 44 // Found the end of the current component. 45 int component_len = i - cur_component_begin; 46 components[cur_component] = 47 url_parse::Component(cur_component_begin, component_len); 48 49 // The next component starts after the dot. 50 cur_component_begin = i + 1; 51 cur_component++; 52 53 // Don't allow empty components (two dots in a row), except we may 54 // allow an empty component at the end (this would indicate that the 55 // input ends in a dot). We also want to error if the component is 56 // empty and it's the only component (cur_component == 1). 57 if (component_len == 0 && (i < end || cur_component == 1)) 58 return false; 59 60 if (i >= end) 61 break; // End of the input. 62 63 if (cur_component == 4) { 64 // Anything else after the 4th component is an error unless it is a 65 // dot that would otherwise be treated as the end of input. 66 if (spec[i] == '.' && i + 1 == end) 67 break; 68 return false; 69 } 70 } else if (static_cast<UCHAR>(spec[i]) >= 0x80 || 71 !IsIPv4Char(static_cast<unsigned char>(spec[i]))) { 72 // Invalid character for an IPv4 address. 73 return false; 74 } 75 } 76 77 // Fill in any unused components. 78 while (cur_component < 4) 79 components[cur_component++] = url_parse::Component(); 80 return true; 81 } 82 83 // Converts an IPv4 component to a 32-bit number, while checking for overflow. 84 // 85 // Possible return values: 86 // - IPV4 - The number was valid, and did not overflow. 87 // - BROKEN - The input was numeric, but too large for a 32-bit field. 88 // - NEUTRAL - Input was not numeric. 89 // 90 // The input is assumed to be ASCII. FindIPv4Components should have stripped 91 // out any input that is greater than 7 bits. The components are assumed 92 // to be non-empty. 93 template<typename CHAR> 94 CanonHostInfo::Family IPv4ComponentToNumber( 95 const CHAR* spec, 96 const url_parse::Component& component, 97 uint32* number) { 98 // Figure out the base 99 SharedCharTypes base; 100 int base_prefix_len = 0; // Size of the prefix for this base. 101 if (spec[component.begin] == '0') { 102 // Either hex or dec, or a standalone zero. 103 if (component.len == 1) { 104 base = CHAR_DEC; 105 } else if (spec[component.begin + 1] == 'X' || 106 spec[component.begin + 1] == 'x') { 107 base = CHAR_HEX; 108 base_prefix_len = 2; 109 } else { 110 base = CHAR_OCT; 111 base_prefix_len = 1; 112 } 113 } else { 114 base = CHAR_DEC; 115 } 116 117 // Extend the prefix to consume all leading zeros. 118 while (base_prefix_len < component.len && 119 spec[component.begin + base_prefix_len] == '0') 120 base_prefix_len++; 121 122 // Put the component, minus any base prefix, into a NULL-terminated buffer so 123 // we can call the standard library. Because leading zeros have already been 124 // discarded, filling the entire buffer is guaranteed to trigger the 32-bit 125 // overflow check. 126 const int kMaxComponentLen = 16; 127 char buf[kMaxComponentLen + 1]; // digits + '\0' 128 int dest_i = 0; 129 for (int i = component.begin + base_prefix_len; i < component.end(); i++) { 130 // We know the input is 7-bit, so convert to narrow (if this is the wide 131 // version of the template) by casting. 132 char input = static_cast<char>(spec[i]); 133 134 // Validate that this character is OK for the given base. 135 if (!IsCharOfType(input, base)) 136 return CanonHostInfo::NEUTRAL; 137 138 // Fill the buffer, if there's space remaining. This check allows us to 139 // verify that all characters are numeric, even those that don't fit. 140 if (dest_i < kMaxComponentLen) 141 buf[dest_i++] = input; 142 } 143 144 buf[dest_i] = '\0'; 145 146 // Use the 64-bit strtoi so we get a big number (no hex, decimal, or octal 147 // number can overflow a 64-bit number in <= 16 characters). 148 uint64 num = _strtoui64(buf, NULL, BaseForType(base)); 149 150 // Check for 32-bit overflow. 151 if (num > kuint32max) 152 return CanonHostInfo::BROKEN; 153 154 // No overflow. Success! 155 *number = static_cast<uint32>(num); 156 return CanonHostInfo::IPV4; 157 } 158 159 // See declaration of IPv4AddressToNumber for documentation. 160 template<typename CHAR> 161 CanonHostInfo::Family DoIPv4AddressToNumber(const CHAR* spec, 162 const url_parse::Component& host, 163 unsigned char address[4], 164 int* num_ipv4_components) { 165 // The identified components. Not all may exist. 166 url_parse::Component components[4]; 167 if (!FindIPv4Components(spec, host, components)) 168 return CanonHostInfo::NEUTRAL; 169 170 // Convert existing components to digits. Values up to 171 // |existing_components| will be valid. 172 uint32 component_values[4]; 173 int existing_components = 0; 174 175 // Set to true if one or more components are BROKEN. BROKEN is only 176 // returned if all components are IPV4 or BROKEN, so, for example, 177 // 12345678912345.de returns NEUTRAL rather than broken. 178 bool broken = false; 179 for (int i = 0; i < 4; i++) { 180 if (components[i].len <= 0) 181 continue; 182 CanonHostInfo::Family family = IPv4ComponentToNumber( 183 spec, components[i], &component_values[existing_components]); 184 185 if (family == CanonHostInfo::BROKEN) { 186 broken = true; 187 } else if (family != CanonHostInfo::IPV4) { 188 // Stop if we hit a non-BROKEN invalid non-empty component. 189 return family; 190 } 191 192 existing_components++; 193 } 194 195 if (broken) 196 return CanonHostInfo::BROKEN; 197 198 // Use that sequence of numbers to fill out the 4-component IP address. 199 200 // First, process all components but the last, while making sure each fits 201 // within an 8-bit field. 202 for (int i = 0; i < existing_components - 1; i++) { 203 if (component_values[i] > kuint8max) 204 return CanonHostInfo::BROKEN; 205 address[i] = static_cast<unsigned char>(component_values[i]); 206 } 207 208 // Next, consume the last component to fill in the remaining bytes. 209 uint32 last_value = component_values[existing_components - 1]; 210 for (int i = 3; i >= existing_components - 1; i--) { 211 address[i] = static_cast<unsigned char>(last_value); 212 last_value >>= 8; 213 } 214 215 // If the last component has residual bits, report overflow. 216 if (last_value != 0) 217 return CanonHostInfo::BROKEN; 218 219 // Tell the caller how many components we saw. 220 *num_ipv4_components = existing_components; 221 222 // Success! 223 return CanonHostInfo::IPV4; 224 } 225 226 // Return true if we've made a final IPV4/BROKEN decision, false if the result 227 // is NEUTRAL, and we could use a second opinion. 228 template<typename CHAR, typename UCHAR> 229 bool DoCanonicalizeIPv4Address(const CHAR* spec, 230 const url_parse::Component& host, 231 CanonOutput* output, 232 CanonHostInfo* host_info) { 233 host_info->family = IPv4AddressToNumber( 234 spec, host, host_info->address, &host_info->num_ipv4_components); 235 236 switch (host_info->family) { 237 case CanonHostInfo::IPV4: 238 // Definitely an IPv4 address. 239 host_info->out_host.begin = output->length(); 240 AppendIPv4Address(host_info->address, output); 241 host_info->out_host.len = output->length() - host_info->out_host.begin; 242 return true; 243 case CanonHostInfo::BROKEN: 244 // Definitely broken. 245 return true; 246 default: 247 // Could be IPv6 or a hostname. 248 return false; 249 } 250 } 251 252 // Helper class that describes the main components of an IPv6 input string. 253 // See the following examples to understand how it breaks up an input string: 254 // 255 // [Example 1]: input = "[::aa:bb]" 256 // ==> num_hex_components = 2 257 // ==> hex_components[0] = Component(3,2) "aa" 258 // ==> hex_components[1] = Component(6,2) "bb" 259 // ==> index_of_contraction = 0 260 // ==> ipv4_component = Component(0, -1) 261 // 262 // [Example 2]: input = "[1:2::3:4:5]" 263 // ==> num_hex_components = 5 264 // ==> hex_components[0] = Component(1,1) "1" 265 // ==> hex_components[1] = Component(3,1) "2" 266 // ==> hex_components[2] = Component(6,1) "3" 267 // ==> hex_components[3] = Component(8,1) "4" 268 // ==> hex_components[4] = Component(10,1) "5" 269 // ==> index_of_contraction = 2 270 // ==> ipv4_component = Component(0, -1) 271 // 272 // [Example 3]: input = "[::ffff:192.168.0.1]" 273 // ==> num_hex_components = 1 274 // ==> hex_components[0] = Component(3,4) "ffff" 275 // ==> index_of_contraction = 0 276 // ==> ipv4_component = Component(8, 11) "192.168.0.1" 277 // 278 // [Example 4]: input = "[1::]" 279 // ==> num_hex_components = 1 280 // ==> hex_components[0] = Component(1,1) "1" 281 // ==> index_of_contraction = 1 282 // ==> ipv4_component = Component(0, -1) 283 // 284 // [Example 5]: input = "[::192.168.0.1]" 285 // ==> num_hex_components = 0 286 // ==> index_of_contraction = 0 287 // ==> ipv4_component = Component(8, 11) "192.168.0.1" 288 // 289 struct IPv6Parsed { 290 // Zero-out the parse information. 291 void reset() { 292 num_hex_components = 0; 293 index_of_contraction = -1; 294 ipv4_component.reset(); 295 } 296 297 // There can be up to 8 hex components (colon separated) in the literal. 298 url_parse::Component hex_components[8]; 299 300 // The count of hex components present. Ranges from [0,8]. 301 int num_hex_components; 302 303 // The index of the hex component that the "::" contraction precedes, or 304 // -1 if there is no contraction. 305 int index_of_contraction; 306 307 // The range of characters which are an IPv4 literal. 308 url_parse::Component ipv4_component; 309 }; 310 311 // Parse the IPv6 input string. If parsing succeeded returns true and fills 312 // |parsed| with the information. If parsing failed (because the input is 313 // invalid) returns false. 314 template<typename CHAR, typename UCHAR> 315 bool DoParseIPv6(const CHAR* spec, 316 const url_parse::Component& host, 317 IPv6Parsed* parsed) { 318 // Zero-out the info. 319 parsed->reset(); 320 321 if (!host.is_nonempty()) 322 return false; 323 324 // The index for start and end of address range (no brackets). 325 int begin = host.begin; 326 int end = host.end(); 327 328 int cur_component_begin = begin; // Start of the current component. 329 330 // Scan through the input, searching for hex components, "::" contractions, 331 // and IPv4 components. 332 for (int i = begin; /* i <= end */; i++) { 333 bool is_colon = spec[i] == ':'; 334 bool is_contraction = is_colon && i < end - 1 && spec[i + 1] == ':'; 335 336 // We reached the end of the current component if we encounter a colon 337 // (separator between hex components, or start of a contraction), or end of 338 // input. 339 if (is_colon || i == end) { 340 int component_len = i - cur_component_begin; 341 342 // A component should not have more than 4 hex digits. 343 if (component_len > 4) 344 return false; 345 346 // Don't allow empty components. 347 if (component_len == 0) { 348 // The exception is when contractions appear at beginning of the 349 // input or at the end of the input. 350 if (!((is_contraction && i == begin) || (i == end && 351 parsed->index_of_contraction == parsed->num_hex_components))) 352 return false; 353 } 354 355 // Add the hex component we just found to running list. 356 if (component_len > 0) { 357 // Can't have more than 8 components! 358 if (parsed->num_hex_components >= 8) 359 return false; 360 361 parsed->hex_components[parsed->num_hex_components++] = 362 url_parse::Component(cur_component_begin, component_len); 363 } 364 } 365 366 if (i == end) 367 break; // Reached the end of the input, DONE. 368 369 // We found a "::" contraction. 370 if (is_contraction) { 371 // There can be at most one contraction in the literal. 372 if (parsed->index_of_contraction != -1) 373 return false; 374 parsed->index_of_contraction = parsed->num_hex_components; 375 ++i; // Consume the colon we peeked. 376 } 377 378 if (is_colon) { 379 // Colons are separators between components, keep track of where the 380 // current component started (after this colon). 381 cur_component_begin = i + 1; 382 } else { 383 if (static_cast<UCHAR>(spec[i]) >= 0x80) 384 return false; // Not ASCII. 385 386 if (!IsHexChar(static_cast<unsigned char>(spec[i]))) { 387 // Regular components are hex numbers. It is also possible for 388 // a component to be an IPv4 address in dotted form. 389 if (IsIPv4Char(static_cast<unsigned char>(spec[i]))) { 390 // Since IPv4 address can only appear at the end, assume the rest 391 // of the string is an IPv4 address. (We will parse this separately 392 // later). 393 parsed->ipv4_component = url_parse::Component( 394 cur_component_begin, end - cur_component_begin); 395 break; 396 } else { 397 // The character was neither a hex digit, nor an IPv4 character. 398 return false; 399 } 400 } 401 } 402 } 403 404 return true; 405 } 406 407 // Verifies the parsed IPv6 information, checking that the various components 408 // add up to the right number of bits (hex components are 16 bits, while 409 // embedded IPv4 formats are 32 bits, and contractions are placeholdes for 410 // 16 or more bits). Returns true if sizes match up, false otherwise. On 411 // success writes the length of the contraction (if any) to 412 // |out_num_bytes_of_contraction|. 413 bool CheckIPv6ComponentsSize(const IPv6Parsed& parsed, 414 int* out_num_bytes_of_contraction) { 415 // Each group of four hex digits contributes 16 bits. 416 int num_bytes_without_contraction = parsed.num_hex_components * 2; 417 418 // If an IPv4 address was embedded at the end, it contributes 32 bits. 419 if (parsed.ipv4_component.is_valid()) 420 num_bytes_without_contraction += 4; 421 422 // If there was a "::" contraction, its size is going to be: 423 // MAX([16bits], [128bits] - num_bytes_without_contraction). 424 int num_bytes_of_contraction = 0; 425 if (parsed.index_of_contraction != -1) { 426 num_bytes_of_contraction = 16 - num_bytes_without_contraction; 427 if (num_bytes_of_contraction < 2) 428 num_bytes_of_contraction = 2; 429 } 430 431 // Check that the numbers add up. 432 if (num_bytes_without_contraction + num_bytes_of_contraction != 16) 433 return false; 434 435 *out_num_bytes_of_contraction = num_bytes_of_contraction; 436 return true; 437 } 438 439 // Converts a hex comonent into a number. This cannot fail since the caller has 440 // already verified that each character in the string was a hex digit, and 441 // that there were no more than 4 characters. 442 template<typename CHAR> 443 uint16 IPv6HexComponentToNumber(const CHAR* spec, 444 const url_parse::Component& component) { 445 DCHECK(component.len <= 4); 446 447 // Copy the hex string into a C-string. 448 char buf[5]; 449 for (int i = 0; i < component.len; ++i) 450 buf[i] = static_cast<char>(spec[component.begin + i]); 451 buf[component.len] = '\0'; 452 453 // Convert it to a number (overflow is not possible, since with 4 hex 454 // characters we can at most have a 16 bit number). 455 return static_cast<uint16>(_strtoui64(buf, NULL, 16)); 456 } 457 458 // Converts an IPv6 address to a 128-bit number (network byte order), returning 459 // true on success. False means that the input was not a valid IPv6 address. 460 template<typename CHAR, typename UCHAR> 461 bool DoIPv6AddressToNumber(const CHAR* spec, 462 const url_parse::Component& host, 463 unsigned char address[16]) { 464 // Make sure the component is bounded by '[' and ']'. 465 int end = host.end(); 466 if (!host.is_nonempty() || spec[host.begin] != '[' || spec[end - 1] != ']') 467 return false; 468 469 // Exclude the square brackets. 470 url_parse::Component ipv6_comp(host.begin + 1, host.len - 2); 471 472 // Parse the IPv6 address -- identify where all the colon separated hex 473 // components are, the "::" contraction, and the embedded IPv4 address. 474 IPv6Parsed ipv6_parsed; 475 if (!DoParseIPv6<CHAR, UCHAR>(spec, ipv6_comp, &ipv6_parsed)) 476 return false; 477 478 // Do some basic size checks to make sure that the address doesn't 479 // specify more than 128 bits or fewer than 128 bits. This also resolves 480 // how may zero bytes the "::" contraction represents. 481 int num_bytes_of_contraction; 482 if (!CheckIPv6ComponentsSize(ipv6_parsed, &num_bytes_of_contraction)) 483 return false; 484 485 int cur_index_in_address = 0; 486 487 // Loop through each hex components, and contraction in order. 488 for (int i = 0; i <= ipv6_parsed.num_hex_components; ++i) { 489 // Append the contraction if it appears before this component. 490 if (i == ipv6_parsed.index_of_contraction) { 491 for (int j = 0; j < num_bytes_of_contraction; ++j) 492 address[cur_index_in_address++] = 0; 493 } 494 // Append the hex component's value. 495 if (i != ipv6_parsed.num_hex_components) { 496 // Get the 16-bit value for this hex component. 497 uint16 number = IPv6HexComponentToNumber<CHAR>( 498 spec, ipv6_parsed.hex_components[i]); 499 // Append to |address|, in network byte order. 500 address[cur_index_in_address++] = (number & 0xFF00) >> 8; 501 address[cur_index_in_address++] = (number & 0x00FF); 502 } 503 } 504 505 // If there was an IPv4 section, convert it into a 32-bit number and append 506 // it to |address|. 507 if (ipv6_parsed.ipv4_component.is_valid()) { 508 // Append the 32-bit number to |address|. 509 int ignored_num_ipv4_components; 510 if (CanonHostInfo::IPV4 != 511 IPv4AddressToNumber(spec, 512 ipv6_parsed.ipv4_component, 513 &address[cur_index_in_address], 514 &ignored_num_ipv4_components)) 515 return false; 516 } 517 518 return true; 519 } 520 521 // Searches for the longest sequence of zeros in |address|, and writes the 522 // range into |contraction_range|. The run of zeros must be at least 16 bits, 523 // and if there is a tie the first is chosen. 524 void ChooseIPv6ContractionRange(const unsigned char address[16], 525 url_parse::Component* contraction_range) { 526 // The longest run of zeros in |address| seen so far. 527 url_parse::Component max_range; 528 529 // The current run of zeros in |address| being iterated over. 530 url_parse::Component cur_range; 531 532 for (int i = 0; i < 16; i += 2) { 533 // Test for 16 bits worth of zero. 534 bool is_zero = (address[i] == 0 && address[i + 1] == 0); 535 536 if (is_zero) { 537 // Add the zero to the current range (or start a new one). 538 if (!cur_range.is_valid()) 539 cur_range = url_parse::Component(i, 0); 540 cur_range.len += 2; 541 } 542 543 if (!is_zero || i == 14) { 544 // Just completed a run of zeros. If the run is greater than 16 bits, 545 // it is a candidate for the contraction. 546 if (cur_range.len > 2 && cur_range.len > max_range.len) { 547 max_range = cur_range; 548 } 549 cur_range.reset(); 550 } 551 } 552 *contraction_range = max_range; 553 } 554 555 // Return true if we've made a final IPV6/BROKEN decision, false if the result 556 // is NEUTRAL, and we could use a second opinion. 557 template<typename CHAR, typename UCHAR> 558 bool DoCanonicalizeIPv6Address(const CHAR* spec, 559 const url_parse::Component& host, 560 CanonOutput* output, 561 CanonHostInfo* host_info) { 562 // Turn the IP address into a 128 bit number. 563 if (!IPv6AddressToNumber(spec, host, host_info->address)) { 564 // If it's not an IPv6 address, scan for characters that should *only* 565 // exist in an IPv6 address. 566 for (int i = host.begin; i < host.end(); i++) { 567 switch (spec[i]) { 568 case '[': 569 case ']': 570 case ':': 571 host_info->family = CanonHostInfo::BROKEN; 572 return true; 573 } 574 } 575 576 // No invalid characters. Could still be IPv4 or a hostname. 577 host_info->family = CanonHostInfo::NEUTRAL; 578 return false; 579 } 580 581 host_info->out_host.begin = output->length(); 582 output->push_back('['); 583 AppendIPv6Address(host_info->address, output); 584 output->push_back(']'); 585 host_info->out_host.len = output->length() - host_info->out_host.begin; 586 587 host_info->family = CanonHostInfo::IPV6; 588 return true; 589 } 590 591 } // namespace 592 593 void AppendIPv4Address(const unsigned char address[4], CanonOutput* output) { 594 for (int i = 0; i < 4; i++) { 595 char str[16]; 596 _itoa_s(address[i], str, 10); 597 598 for (int ch = 0; str[ch] != 0; ch++) 599 output->push_back(str[ch]); 600 601 if (i != 3) 602 output->push_back('.'); 603 } 604 } 605 606 void AppendIPv6Address(const unsigned char address[16], CanonOutput* output) { 607 // We will output the address according to the rules in: 608 // http://tools.ietf.org/html/draft-kawamura-ipv6-text-representation-01#section-4 609 610 // Start by finding where to place the "::" contraction (if any). 611 url_parse::Component contraction_range; 612 ChooseIPv6ContractionRange(address, &contraction_range); 613 614 for (int i = 0; i <= 14;) { 615 // We check 2 bytes at a time, from bytes (0, 1) to (14, 15), inclusive. 616 DCHECK(i % 2 == 0); 617 if (i == contraction_range.begin && contraction_range.len > 0) { 618 // Jump over the contraction. 619 if (i == 0) 620 output->push_back(':'); 621 output->push_back(':'); 622 i = contraction_range.end(); 623 } else { 624 // Consume the next 16 bits from |address|. 625 int x = address[i] << 8 | address[i + 1]; 626 627 i += 2; 628 629 // Stringify the 16 bit number (at most requires 4 hex digits). 630 char str[5]; 631 _itoa_s(x, str, 16); 632 for (int ch = 0; str[ch] != 0; ++ch) 633 output->push_back(str[ch]); 634 635 // Put a colon after each number, except the last. 636 if (i < 16) 637 output->push_back(':'); 638 } 639 } 640 } 641 642 bool FindIPv4Components(const char* spec, 643 const url_parse::Component& host, 644 url_parse::Component components[4]) { 645 return DoFindIPv4Components<char, unsigned char>(spec, host, components); 646 } 647 648 bool FindIPv4Components(const base::char16* spec, 649 const url_parse::Component& host, 650 url_parse::Component components[4]) { 651 return DoFindIPv4Components<base::char16, base::char16>( 652 spec, host, components); 653 } 654 655 void CanonicalizeIPAddress(const char* spec, 656 const url_parse::Component& host, 657 CanonOutput* output, 658 CanonHostInfo* host_info) { 659 if (DoCanonicalizeIPv4Address<char, unsigned char>( 660 spec, host, output, host_info)) 661 return; 662 if (DoCanonicalizeIPv6Address<char, unsigned char>( 663 spec, host, output, host_info)) 664 return; 665 } 666 667 void CanonicalizeIPAddress(const base::char16* spec, 668 const url_parse::Component& host, 669 CanonOutput* output, 670 CanonHostInfo* host_info) { 671 if (DoCanonicalizeIPv4Address<base::char16, base::char16>( 672 spec, host, output, host_info)) 673 return; 674 if (DoCanonicalizeIPv6Address<base::char16, base::char16>( 675 spec, host, output, host_info)) 676 return; 677 } 678 679 CanonHostInfo::Family IPv4AddressToNumber(const char* spec, 680 const url_parse::Component& host, 681 unsigned char address[4], 682 int* num_ipv4_components) { 683 return DoIPv4AddressToNumber<char>(spec, host, address, num_ipv4_components); 684 } 685 686 CanonHostInfo::Family IPv4AddressToNumber(const base::char16* spec, 687 const url_parse::Component& host, 688 unsigned char address[4], 689 int* num_ipv4_components) { 690 return DoIPv4AddressToNumber<base::char16>( 691 spec, host, address, num_ipv4_components); 692 } 693 694 bool IPv6AddressToNumber(const char* spec, 695 const url_parse::Component& host, 696 unsigned char address[16]) { 697 return DoIPv6AddressToNumber<char, unsigned char>(spec, host, address); 698 } 699 700 bool IPv6AddressToNumber(const base::char16* spec, 701 const url_parse::Component& host, 702 unsigned char address[16]) { 703 return DoIPv6AddressToNumber<base::char16, base::char16>(spec, host, address); 704 } 705 706 } // namespace url_canon 707