@@ -10,6 +10,12 @@ namespace tns {
1010 URLSearchParamsImpl::URLSearchParamsImpl (ada::url_search_params params) : params_(params) {}
1111
1212 URLSearchParamsImpl *URLSearchParamsImpl::GetPointer (v8::Local<v8::Object> object) {
13+ // A foreign receiver (e.g. entries.call({})) has no internal field, and
14+ // reading one that is not there is undefined behavior, so check first
15+ // and report not-a-URLSearchParams instead.
16+ if (object->InternalFieldCount () < 1 ) {
17+ return nullptr ;
18+ }
1319 auto ptr = object->GetAlignedPointerFromInternalField (0 );
1420 if (ptr == nullptr ) {
1521 return nullptr ;
@@ -115,6 +121,7 @@ namespace tns {
115121 const char *const kStateSource = " src" ;
116122 const char *const kStateIndex = " idx" ;
117123 const char *const kStateKind = " knd" ;
124+ const char *const kStateIterator = " itr" ;
118125
119126 void IteratorSelf (const v8::FunctionCallbackInfo<v8::Value> &args) {
120127 // An iterator is itself iterable (iterator[@@iterator]() === iterator),
@@ -127,6 +134,17 @@ namespace tns {
127134 auto context = isolate->GetCurrentContext ();
128135 auto state = args.Data ().As <v8::Object>();
129136
137+ // WebIDL brand check: next() must be invoked on the iterator it was
138+ // created on, so a detached next() throws instead of advancing the
139+ // captured state.
140+ v8::Local<v8::Value> iteratorValue;
141+ if (!state->Get (context, ArgConverter::ConvertToV8String (isolate, kStateIterator ))
142+ .ToLocal (&iteratorValue) ||
143+ !iteratorValue->StrictEquals (args.This ())) {
144+ ThrowTypeError (isolate, " Illegal invocation" );
145+ return ;
146+ }
147+
130148 auto indexKey = ArgConverter::ConvertToV8String (isolate, kStateIndex );
131149 v8::Local<v8::Value> sourceValue;
132150 v8::Local<v8::Value> indexValue;
@@ -180,6 +198,13 @@ namespace tns {
180198 auto isolate = args.GetIsolate ();
181199 auto context = isolate->GetCurrentContext ();
182200
201+ // WebIDL brand check: entries()/keys()/values() require a genuine
202+ // URLSearchParams receiver, so e.g. entries.call({}) throws.
203+ if (URLSearchParamsImpl::GetPointer (args.This ()) == nullptr ) {
204+ ThrowTypeError (isolate, " Illegal invocation" );
205+ return ;
206+ }
207+
183208 auto state = v8::Object::New (isolate);
184209 state->Set (context, ArgConverter::ConvertToV8String (isolate, kStateSource ),
185210 args.This ()).Check ();
@@ -196,6 +221,9 @@ namespace tns {
196221 }
197222
198223 auto iterator = v8::Object::New (isolate);
224+ // Recorded in the hidden state so next() can brand-check its receiver.
225+ state->Set (context, ArgConverter::ConvertToV8String (isolate, kStateIterator ),
226+ iterator).Check ();
199227 iterator->Set (context, ArgConverter::ConvertToV8String (isolate, " next" ), nextFn).Check ();
200228 iterator->Set (context, v8::Symbol::GetIterator (isolate), selfFn).Check ();
201229 iterator->DefineOwnProperty (context, v8::Symbol::GetToStringTag (isolate),
@@ -525,7 +553,13 @@ namespace tns {
525553 if (ptr == nullptr ) {
526554 return ;
527555 }
528- auto key = ArgConverter::ConvertToString (args[0 ].As <v8::String>());
556+ // The name is a USVString (url.bs:3861): coerce it like the optional
557+ // value below instead of assuming a string (a Symbol or throwing
558+ // toString leaves the pending exception and aborts).
559+ std::string key;
560+ if (!ValueToString (args.GetIsolate ()->GetCurrentContext (), args[0 ], key)) {
561+ return ;
562+ }
529563 // Spec delete(name, value): when the value argument is given, remove only
530564 // tuples matching BOTH name and value (url.bs:4000). The value is a
531565 // USVString, so coerce via ValueToString (number/boolean -> string; a
@@ -590,8 +624,13 @@ namespace tns {
590624 args.GetReturnValue ().SetUndefined ();
591625 return ;
592626 }
593- auto key = args[0 ].As <v8::String>();
594- auto value = ptr->GetURLSearchParams ()->get (ArgConverter::ConvertToString (key));
627+ // The name is a USVString (url.bs:3862); a Symbol or throwing toString
628+ // leaves the pending exception and aborts.
629+ std::string key;
630+ if (!ValueToString (isolate->GetCurrentContext (), args[0 ], key)) {
631+ return ;
632+ }
633+ auto value = ptr->GetURLSearchParams ()->get (key);
595634 if (value.has_value ()) {
596635 auto ret = ArgConverter::ConvertToV8String (isolate, std::string (value.value ()));
597636 args.GetReturnValue ().Set (ret);
@@ -610,8 +649,13 @@ namespace tns {
610649 args.GetReturnValue ().Set (v8::Array::New (isolate));
611650 return ;
612651 }
613- auto key = args[0 ].As <v8::String>();
614- auto values = ptr->GetURLSearchParams ()->get_all (ArgConverter::ConvertToString (key));
652+ // The name is a USVString (url.bs:3863); a Symbol or throwing toString
653+ // leaves the pending exception and aborts.
654+ std::string key;
655+ if (!ValueToString (context, args[0 ], key)) {
656+ return ;
657+ }
658+ auto values = ptr->GetURLSearchParams ()->get_all (key);
615659 auto ret = v8::Array::New (isolate, values.size ());
616660 size_t i = 0 ;
617661 for (auto item: values) {
@@ -626,7 +670,13 @@ namespace tns {
626670 args.GetReturnValue ().Set (false );
627671 return ;
628672 }
629- auto key = args[0 ].As <v8::String>();
673+ // The name is a USVString (url.bs:3864): coerce it like the optional
674+ // value below instead of assuming a string (a Symbol or throwing
675+ // toString leaves the pending exception and aborts).
676+ std::string key;
677+ if (!ValueToString (args.GetIsolate ()->GetCurrentContext (), args[0 ], key)) {
678+ return ;
679+ }
630680 // Spec has(name, value): when the value argument is given, return true
631681 // only for a tuple matching BOTH name and value (url.bs:4028). The value
632682 // is a USVString, so coerce via ValueToString (number/boolean -> string;
@@ -640,9 +690,9 @@ namespace tns {
640690 if (!ValueToString (args.GetIsolate ()->GetCurrentContext (), args[1 ], filter)) {
641691 return ; // coercion threw (Symbol / throwing toString)
642692 }
643- value = ptr->GetURLSearchParams ()->has (ArgConverter::ConvertToString ( key) , filter);
693+ value = ptr->GetURLSearchParams ()->has (key, filter);
644694 } else {
645- value = ptr->GetURLSearchParams ()->has (ArgConverter::ConvertToString ( key) );
695+ value = ptr->GetURLSearchParams ()->has (key);
646696 }
647697
648698 args.GetReturnValue ().Set (value);
0 commit comments