66#include " node_errors.h"
77#include " node_hash.h"
88#include " node_sockaddr-inl.h" // NOLINT(build/include_inline)
9+ #include " node_sockaddr_parser.h"
910#include " uv.h"
1011
1112#include < memory>
13+ #include < optional>
1214#include < string>
15+ #include < string_view>
1316#include < vector>
1417
1518namespace node {
@@ -67,6 +70,31 @@ bool SocketAddress::New(int32_t family,
6770 family, host, port, reinterpret_cast <sockaddr_storage*>(addr->storage ()));
6871}
6972
73+ bool SocketAddress::Parse (std::string_view input, SocketAddress* addr) {
74+ std::optional<sockaddr_parser::parse_result> parsed =
75+ sockaddr_parser::ParseSocketAddress (input);
76+ if (!parsed.has_value ()) return false ;
77+
78+ CHECK_LE (parsed->host .size (), sockaddr_parser::kMaxHostLength );
79+
80+ char host[sockaddr_parser::kMaxHostLength + 1 ];
81+ host[parsed->host .copy (host, parsed->host .size ())] = ' \0 ' ;
82+
83+ if (!New (parsed->is_ipv6 ? AF_INET6 : AF_INET , host, parsed->port , addr)) {
84+ return false ;
85+ }
86+
87+ // libuv resolves a zone id as an interface name, never as a number.
88+ // TODO(@araujogui): sin6_scope_id is neither exposed to JS nor hashed, so
89+ // scoped addresses do not round-trip and collide in BlockList.
90+ if (parsed->is_ipv6 ) {
91+ reinterpret_cast <sockaddr_in6*>(addr->storage ())->sin6_scope_id =
92+ parsed->scope_id ;
93+ }
94+
95+ return true ;
96+ }
97+
7098size_t SocketAddress::Hash::operator ()(const SocketAddress& addr) const {
7199 // Hash only the meaningful bytes (family + port + address), not the
72100 // full 128-byte sockaddr_storage.
@@ -82,6 +110,8 @@ size_t SocketAddress::Hash::operator()(const SocketAddress& addr) const {
82110 case AF_INET6 : {
83111 const sockaddr_in6* ipv6 =
84112 reinterpret_cast <const sockaddr_in6*>(addr.raw ());
113+ // TODO(@araujogui): sin6_scope_id is not hashed, so addresses that
114+ // differ only by zone id collide.
85115 uint8_t buf[18 ];
86116 memcpy (buf, &ipv6->sin6_port , 2 );
87117 memcpy (buf + 2 , &ipv6->sin6_addr , 16 );
@@ -757,6 +787,8 @@ void SocketAddressBase::Initialize(Environment* env, Local<Object> target) {
757787 " SocketAddress" ,
758788 GetConstructorTemplate (env),
759789 SetConstructorFunctionFlag::NONE );
790+
791+ SetMethod (env->context (), target, " parseSocketAddress" , Parse);
760792}
761793
762794BaseObjectPtr<SocketAddressBase> SocketAddressBase::Create (
@@ -795,6 +827,20 @@ void SocketAddressBase::New(const FunctionCallbackInfo<Value>& args) {
795827 new SocketAddressBase (env, args.This (), std::move (addr));
796828}
797829
830+ void SocketAddressBase::Parse (const FunctionCallbackInfo<Value>& args) {
831+ Environment* env = Environment::GetCurrent (args);
832+ CHECK (args[0 ]->IsString ()); // input
833+
834+ Utf8Value input (env->isolate (), args[0 ]);
835+
836+ auto addr = std::make_shared<SocketAddress>();
837+ if (!SocketAddress::Parse (input.ToStringView (), addr.get ())) return ;
838+
839+ BaseObjectPtr<SocketAddressBase> base =
840+ SocketAddressBase::Create (env, std::move (addr));
841+ if (base) args.GetReturnValue ().Set (base->object ());
842+ }
843+
798844void SocketAddressBase::Detail (const FunctionCallbackInfo<Value>& args) {
799845 Environment* env = Environment::GetCurrent (args);
800846 CHECK (args[0 ]->IsObject ());
0 commit comments