88#include " node_hash.h"
99#include " node_sockaddr-inl.h" // NOLINT(build/include_inline)
1010#include " uv.h"
11+ #include " v8-fast-api-calls.h"
12+
13+ #include < cstring>
1114
1215#include < memory>
1316#include < string>
@@ -18,6 +21,8 @@ namespace node {
1821using v8::Array;
1922using v8::CFunction;
2023using v8::Context;
24+ using v8::FastApiCallbackOptions;
25+ using v8::FastOneByteString;
2126using v8::FunctionCallbackInfo;
2227using v8::FunctionTemplate;
2328using v8::Int32;
@@ -1032,6 +1037,53 @@ void SocketAddressBlockListWrap::CheckString(
10321037 args.GetReturnValue ().Set (wrap->blocklist_ ->Apply (addr));
10331038}
10341039
1040+ bool SocketAddressBlockListWrap::FastCheckString (
1041+ Local<Object> receiver,
1042+ const FastOneByteString& address,
1043+ int32_t family,
1044+ // NOLINTNEXTLINE(runtime/references) This is V8 api.
1045+ FastApiCallbackOptions& options) {
1046+ // FastOneByteString is not NUL-terminated. Copy onto the stack
1047+ // before any other work: a GC would invalidate `address`.
1048+ //
1049+ // uv_ip6_addr only needs the address part (≤39 chars) plus an
1050+ // optional %zone. A zone longer than UV_IF_NAMESIZE is unknown
1051+ // (scope_id 0), same as omitting it. Keep that behavior when the
1052+ // full string does not fit so Fast API and CheckString agree.
1053+ constexpr size_t kMax = INET6_ADDRSTRLEN + UV_IF_NAMESIZE ;
1054+ char buf[kMax ];
1055+ if (address.length < kMax ) {
1056+ memcpy (buf, address.data , address.length );
1057+ buf[address.length ] = ' \0 ' ;
1058+ } else if (family == AF_INET6 ) {
1059+ // uv_ip4_addr rejects %zone. Only IPv6 may drop an overlong zone
1060+ // (unknown zone → scope_id 0, same as uv_ip6_addr).
1061+ // uv_ip6_addr copies the address part into a 40-byte buffer
1062+ // (39 chars + NUL). A 40+ char prefix (mixed notation) is
1063+ // truncated and fails inet_pton — do not keep the full prefix.
1064+ const char * percent =
1065+ static_cast <const char *>(memchr (address.data , ' %' , address.length ));
1066+ if (percent == nullptr ) return false ;
1067+ const size_t addr_len = static_cast <size_t >(percent - address.data );
1068+ if (addr_len >= 40 ) return false ;
1069+ memcpy (buf, address.data , addr_len);
1070+ buf[addr_len] = ' \0 ' ;
1071+ } else {
1072+ return false ;
1073+ }
1074+ USE (options);
1075+
1076+ TRACK_V8_FAST_API_CALL (" blocklist.checkString" );
1077+ SocketAddressBlockListWrap* wrap =
1078+ FromJSObject<SocketAddressBlockListWrap>(receiver);
1079+ SocketAddress addr;
1080+ if (!SocketAddress::New (family, buf, 0 , &addr)) return false ;
1081+ return wrap->blocklist_ ->Apply (addr);
1082+ }
1083+
1084+ CFunction SocketAddressBlockListWrap::fast_check_string_ (
1085+ CFunction::Make (&SocketAddressBlockListWrap::FastCheckString));
1086+
10351087void SocketAddressBlockListWrap::GetRules (
10361088 const FunctionCallbackInfo<Value>& args) {
10371089 Environment* env = Environment::GetCurrent (args);
@@ -1087,7 +1139,11 @@ Local<FunctionTemplate> SocketAddressBlockListWrap::GetConstructorTemplate(
10871139 SetProtoMethod (isolate, tmpl, " removeSubnet" , RemoveSubnet);
10881140 SetFastMethod (
10891141 isolate, tmpl->PrototypeTemplate (), " check" , Check, &fast_check_);
1090- SetProtoMethod (isolate, tmpl, " checkString" , CheckString);
1142+ SetFastMethod (isolate,
1143+ tmpl->PrototypeTemplate (),
1144+ " checkString" ,
1145+ CheckString,
1146+ &fast_check_string_);
10911147 SetProtoMethod (isolate, tmpl, " getRules" , GetRules);
10921148 SetProtoMethodNoSideEffect (isolate, tmpl, " getSize" , GetSize);
10931149 SetProtoMethod (isolate, tmpl, " clear" , Clear);
0 commit comments