Skip to content

Commit e76b5ef

Browse files
committed
url,src: simplify ipv6 logic by using uv_inet_pton
1 parent 4c508f5 commit e76b5ef

File tree

1 file changed

+19
-109
lines changed

1 file changed

+19
-109
lines changed

src/node_url.cc

Lines changed: 19 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ constexpr char kEOL = -1;
4848
// Used in ToUSVString().
4949
constexpr char16_t kUnicodeReplacementCharacter = 0xFFFD;
5050

51+
#define NS_IN6ADDRSZ 16
52+
#define NS_INT16SZ 2
53+
5154
// https://url.spec.whatwg.org/#concept-host
5255
class 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

800803
void 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

Comments
 (0)