@@ -48,6 +48,9 @@ constexpr char kEOL = -1;
4848// Used in ToUSVString().
4949constexpr char16_t kUnicodeReplacementCharacter = 0xFFFD ;
5050
51+ #define NS_IN6ADDRSZ 16
52+ #define NS_INT16SZ 2
53+
5154// https://url.spec.whatwg.org/#concept-host
5255class URLHost {
5356 public:
@@ -78,7 +81,7 @@ class URLHost {
7881 union Value {
7982 std::string domain_or_opaque;
8083 uint32_t ipv4;
81- uint16_t ipv6[8 ];
84+ uint16_t ipv6[NS_IN6ADDRSZ / NS_INT16SZ ];
8285
8386 ~Value () {}
8487 Value () : ipv4 (0 ) {}
@@ -799,117 +802,24 @@ bool ToASCII(const std::string& input, std::string* output) {
799802
800803void URLHost::ParseIPv6Host (const char * input, size_t length) {
801804 CHECK_EQ (type_, HostType::H_FAILED);
802- unsigned size = arraysize (value_.ipv6 );
803- for (unsigned n = 0 ; n < size; n++)
804- value_.ipv6 [n] = 0 ;
805- uint16_t * piece_pointer = &value_.ipv6 [0 ];
806- uint16_t * const buffer_end = piece_pointer + size;
807- uint16_t * compress_pointer = nullptr ;
808- const char * pointer = input;
809- const char * end = pointer + length;
810- unsigned value, len, numbers_seen;
811- char ch = pointer < end ? pointer[0 ] : kEOL ;
812- if (ch == ' :' ) {
813- if (length < 2 || pointer[1 ] != ' :' )
814- return ;
815- pointer += 2 ;
816- ch = pointer < end ? pointer[0 ] : kEOL ;
817- piece_pointer++;
818- compress_pointer = piece_pointer;
819- }
820- while (ch != kEOL ) {
821- if (piece_pointer >= buffer_end)
822- return ;
823- if (ch == ' :' ) {
824- if (compress_pointer != nullptr )
825- return ;
826- pointer++;
827- ch = pointer < end ? pointer[0 ] : kEOL ;
828- piece_pointer++;
829- compress_pointer = piece_pointer;
830- continue ;
831- }
832- value = 0 ;
833- len = 0 ;
834- while (len < 4 && IsASCIIHexDigit (ch)) {
835- value = value * 0x10 + hex2bin (ch);
836- pointer++;
837- ch = pointer < end ? pointer[0 ] : kEOL ;
838- len++;
839- }
840- switch (ch) {
841- case ' .' :
842- if (len == 0 )
843- return ;
844- pointer -= len;
845- ch = pointer < end ? pointer[0 ] : kEOL ;
846- if (piece_pointer > buffer_end - 2 )
847- return ;
848- numbers_seen = 0 ;
849- while (ch != kEOL ) {
850- value = 0xffffffff ;
851- if (numbers_seen > 0 ) {
852- if (ch == ' .' && numbers_seen < 4 ) {
853- pointer++;
854- ch = pointer < end ? pointer[0 ] : kEOL ;
855- } else {
856- return ;
857- }
858- }
859- if (!IsASCIIDigit (ch))
860- return ;
861- while (IsASCIIDigit (ch)) {
862- unsigned number = ch - ' 0' ;
863- if (value == 0xffffffff ) {
864- value = number;
865- } else if (value == 0 ) {
866- return ;
867- } else {
868- value = value * 10 + number;
869- }
870- if (value > 255 )
871- return ;
872- pointer++;
873- ch = pointer < end ? pointer[0 ] : kEOL ;
874- }
875- *piece_pointer = *piece_pointer * 0x100 + value;
876- numbers_seen++;
877- if (numbers_seen == 2 || numbers_seen == 4 )
878- piece_pointer++;
879- }
880- if (numbers_seen != 4 )
881- return ;
882- continue ;
883- case ' :' :
884- pointer++;
885- ch = pointer < end ? pointer[0 ] : kEOL ;
886- if (ch == kEOL )
887- return ;
888- break ;
889- case kEOL :
890- break ;
891- default :
892- return ;
893- }
894- *piece_pointer = value;
895- piece_pointer++;
896- }
897805
898- if (compress_pointer != nullptr ) {
899- int64_t swaps = piece_pointer - compress_pointer;
900- piece_pointer = buffer_end - 1 ;
901- while (piece_pointer != &value_.ipv6 [0 ] && swaps > 0 ) {
902- uint16_t temp = *piece_pointer;
903- uint16_t * swap_piece = compress_pointer + swaps - 1 ;
904- *piece_pointer = *swap_piece;
905- *swap_piece = temp;
906- piece_pointer--;
907- swaps--;
908- }
909- } else if (compress_pointer == nullptr &&
910- piece_pointer != buffer_end) {
806+ unsigned char buf[sizeof (struct in6_addr )];
807+ MaybeStackBuffer<char > ipv6 (length + 1 );
808+ *(*ipv6 + length) = 0 ;
809+ memset (buf, 0 , sizeof (buf));
810+ memcpy (*ipv6, input, sizeof (const char ) * length);
811+
812+ int ret = uv_inet_pton (AF_INET6, *ipv6, buf);
813+
814+ if (ret != 0 ) {
911815 return ;
912816 }
817+
818+ // Ref: https://sourceware.org/git/?p=glibc.git;a=blob;f=resolv/inet_ntop.c;h=c4d38c0f951013e51a4fc6eaa8a9b82e146abe5a;hb=HEAD#l119
819+ for (int i = 0 ; i < NS_IN6ADDRSZ; i += 2 ) {
820+ value_.ipv6 [i >> 1 ] = (buf[i] << 8 ) | buf[i + 1 ];
821+ }
822+
913823 type_ = HostType::H_IPV6;
914824}
915825
0 commit comments