[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMWindowCustom.cpp
1 /*
2  * Copyright (C) 2007-2010, 2016 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Google Inc. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22 #include "JSDOMWindowCustom.h"
23
24 #include "DOMWindowIndexedDatabase.h"
25 #include "Frame.h"
26 #include "HTMLCollection.h"
27 #include "HTMLDocument.h"
28 #include "JSEvent.h"
29 #include "JSEventListener.h"
30 #include "JSHTMLAudioElement.h"
31 #include "JSHTMLCollection.h"
32 #include "JSHTMLOptionElement.h"
33 #include "JSIDBFactory.h"
34 #include "JSImageConstructor.h"
35 #include "JSMessagePortCustom.h"
36 #include "JSWorker.h"
37 #include "Location.h"
38 #include "RuntimeEnabledFeatures.h"
39 #include "ScheduledAction.h"
40 #include "Settings.h"
41
42 #if ENABLE(USER_MESSAGE_HANDLERS)
43 #include "JSWebKitNamespace.h"
44 #endif
45
46 using namespace JSC;
47
48 namespace WebCore {
49
50 EncodedJSValue JSC_HOST_CALL jsDOMWindowInstanceFunctionShowModalDialog(ExecState*);
51
52 void JSDOMWindow::visitAdditionalChildren(SlotVisitor& visitor)
53 {
54     if (Frame* frame = wrapped().frame())
55         visitor.addOpaqueRoot(frame);
56 }
57
58 #if ENABLE(USER_MESSAGE_HANDLERS)
59 static EncodedJSValue jsDOMWindowWebKit(ExecState* exec, EncodedJSValue thisValue, PropertyName)
60 {
61     JSDOMWindow* castedThis = toJSDOMWindow(JSValue::decode(thisValue));
62     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->wrapped()))
63         return JSValue::encode(jsUndefined());
64     return JSValue::encode(toJS(exec, castedThis->globalObject(), castedThis->wrapped().webkitNamespace()));
65 }
66 #endif
67
68 static bool jsDOMWindowGetOwnPropertySlotRestrictedAccess(JSDOMWindow* thisObject, Frame* frame, ExecState* exec, PropertyName propertyName, PropertySlot& slot, const String& errorMessage)
69 {
70     VM& vm = exec->vm();
71     auto scope = DECLARE_THROW_SCOPE(vm);
72
73     // We don't want any properties other than "close" and "closed" on a frameless window
74     // (i.e. one whose page got closed, or whose iframe got removed).
75     // FIXME: This handling for frameless windows duplicates similar behaviour for cross-origin
76     // access below; we should try to find a way to merge the two.
77     if (!frame) {
78         if (propertyName == exec->propertyNames().closed) {
79             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, jsDOMWindowClosed);
80             return true;
81         }
82         if (propertyName == exec->propertyNames().close) {
83             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionClose, 0>);
84             return true;
85         }
86
87         // FIXME: We should have a message here that explains why the property access/function call was
88         // not allowed. 
89         slot.setUndefined();
90         return true;
91     }
92
93     // These are the functions we allow access to cross-origin (DoNotCheckSecurity in IDL).
94     // Always provide the original function, on a fresh uncached function object.
95     if (propertyName == exec->propertyNames().blur) {
96         slot.setCustom(thisObject, ReadOnly | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionBlur, 0>);
97         return true;
98     }
99     if (propertyName == exec->propertyNames().close) {
100         slot.setCustom(thisObject, ReadOnly | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionClose, 0>);
101         return true;
102     }
103     if (propertyName == exec->propertyNames().focus) {
104         slot.setCustom(thisObject, ReadOnly | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionFocus, 0>);
105         return true;
106     }
107     if (propertyName == exec->propertyNames().postMessage) {
108         slot.setCustom(thisObject, ReadOnly | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionPostMessage, 2>);
109         return true;
110     }
111
112     // When accessing cross-origin known Window properties, we always use the original property getter,
113     // even if the property was removed / redefined. As of early 2016, this matches Firefox and Chrome's
114     // behavior.
115     if (auto* entry = JSDOMWindow::info()->staticPropHashTable->entry(propertyName)) {
116         // Only allow access to these specific properties.
117         if (propertyName == exec->propertyNames().location
118             || propertyName == exec->propertyNames().closed
119             || propertyName == exec->propertyNames().length
120             || propertyName == exec->propertyNames().self
121             || propertyName == exec->propertyNames().window
122             || propertyName == exec->propertyNames().frames
123             || propertyName == exec->propertyNames().opener
124             || propertyName == exec->propertyNames().parent
125             || propertyName == exec->propertyNames().top) {
126             bool shouldExposeSetter = propertyName == exec->propertyNames().location;
127             CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, entry->propertyGetter(), shouldExposeSetter ? entry->propertyPutter() : nullptr);
128             slot.setCustomGetterSetter(thisObject, DontEnum | CustomAccessor, customGetterSetter);
129             return true;
130         }
131
132         // For any other entries in the static property table, deny access. (Early return also prevents
133         // named getter from returning frames with matching names - this seems a little questionable, see
134         // FIXME comment on prototype search below.)
135         throwSecurityError(*exec, scope, errorMessage);
136         slot.setUndefined();
137         return true;
138     }
139
140     // Check for child frames by name before built-in properties to match Mozilla. This does
141     // not match IE, but some sites end up naming frames things that conflict with window
142     // properties that are in Moz but not IE. Since we have some of these, we have to do it
143     // the Moz way.
144     if (auto* scopedChild = frame->tree().scopedChild(propertyNameToAtomicString(propertyName))) {
145         slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, toJS(exec, scopedChild->document()->domWindow()));
146         return true;
147     }
148
149     throwSecurityError(*exec, scope, errorMessage);
150     slot.setUndefined();
151     return true;
152 }
153
154 // Property access sequence is:
155 // (1) indexed properties,
156 // (2) regular own properties,
157 // (3) named properties (in fact, these shouldn't be on the window, should be on the NPO).
158 bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)
159 {
160     // (1) First, indexed properties.
161     // Hand off all indexed access to getOwnPropertySlotByIndex, which supports the indexed getter.
162     if (std::optional<unsigned> index = parseIndex(propertyName))
163         return getOwnPropertySlotByIndex(object, state, index.value(), slot);
164
165     auto* thisObject = jsCast<JSDOMWindow*>(object);
166     auto* frame = thisObject->wrapped().frame();
167
168     // Hand off all cross-domain/frameless access to jsDOMWindowGetOwnPropertySlotRestrictedAccess.
169     String errorMessage;
170     if (!frame || !BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage))
171         return jsDOMWindowGetOwnPropertySlotRestrictedAccess(thisObject, frame, state, propertyName, slot, errorMessage);
172     
173     // FIXME: this need more explanation.
174     // (Particularly, is it correct that this exists here but not in getOwnPropertySlotByIndex?)
175     slot.setWatchpointSet(thisObject->m_windowCloseWatchpoints);
176
177     // (2) Regular own properties.
178     PropertySlot slotCopy = slot;
179     if (Base::getOwnPropertySlot(thisObject, state, propertyName, slot)) {
180         // Detect when we're getting the property 'showModalDialog', this is disabled, and has its original value.
181         bool isShowModalDialogAndShouldHide = propertyName == state->propertyNames().showModalDialog
182             && !DOMWindow::canShowModalDialog(frame)
183             && slot.isValue() && isHostFunction(slot.getValue(state, propertyName), jsDOMWindowInstanceFunctionShowModalDialog);
184         // Unless we're in the showModalDialog special case, we're done.
185         if (!isShowModalDialogAndShouldHide)
186             return true;
187         slot = slotCopy;
188     }
189
190 #if ENABLE(USER_MESSAGE_HANDLERS)
191     if (propertyName == state->propertyNames().webkit && thisObject->wrapped().shouldHaveWebKitNamespaceForWorld(thisObject->world())) {
192         slot.setCacheableCustom(thisObject, DontDelete | ReadOnly, jsDOMWindowWebKit);
193         return true;
194     }
195 #endif
196
197     return false;
198 }
199
200 // Property access sequence is:
201 // (1) indexed properties,
202 // (2) regular own properties,
203 // (3) named properties (in fact, these shouldn't be on the window, should be on the NPO).
204 bool JSDOMWindow::getOwnPropertySlotByIndex(JSObject* object, ExecState* state, unsigned index, PropertySlot& slot)
205 {
206     auto* thisObject = jsCast<JSDOMWindow*>(object);
207     auto* frame = thisObject->wrapped().frame();
208
209     // Indexed getters take precendence over regular properties, so caching would be invalid.
210     slot.disableCaching();
211
212     // (1) First, indexed properties.
213     // These are also allowed cross-orgin, so come before the access check.
214     if (frame && index < frame->tree().scopedChildCount()) {
215         slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, toJS(state, frame->tree().scopedChild(index)->document()->domWindow()));
216         return true;
217     }
218
219     // Hand off all cross-domain/frameless access to jsDOMWindowGetOwnPropertySlotRestrictedAccess.
220     String errorMessage;
221     if (!frame || !BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage))
222         return jsDOMWindowGetOwnPropertySlotRestrictedAccess(thisObject, frame, state, Identifier::from(state, index), slot, errorMessage);
223
224     // (2) Regular own properties.
225     return Base::getOwnPropertySlotByIndex(thisObject, state, index, slot);
226 }
227
228 bool JSDOMWindow::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
229 {
230     VM& vm = state->vm();
231     auto scope = DECLARE_THROW_SCOPE(vm);
232
233     auto* thisObject = jsCast<JSDOMWindow*>(cell);
234     if (!thisObject->wrapped().frame())
235         return false;
236
237     String errorMessage;
238     if (!BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage)) {
239         // We only allow setting "location" attribute cross-origin.
240         if (propertyName == state->propertyNames().location) {
241             bool putResult = false;
242             if (lookupPut(state, propertyName, thisObject, value, *s_info.staticPropHashTable, slot, putResult))
243                 return putResult;
244             return false;
245         }
246         throwSecurityError(*state, scope, errorMessage);
247         return false;
248     }
249
250     return Base::put(thisObject, state, propertyName, value, slot);
251 }
252
253 bool JSDOMWindow::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)
254 {
255     auto* thisObject = jsCast<JSDOMWindow*>(cell);
256     if (!thisObject->wrapped().frame() || !BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped()))
257         return false;
258     
259     return Base::putByIndex(thisObject, exec, index, value, shouldThrow);
260 }
261
262 bool JSDOMWindow::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
263 {
264     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
265     // Only allow deleting properties by frames in the same origin.
266     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError))
267         return false;
268     return Base::deleteProperty(thisObject, exec, propertyName);
269 }
270
271 bool JSDOMWindow::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
272 {
273     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
274     // Only allow deleting properties by frames in the same origin.
275     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError))
276         return false;
277     return Base::deletePropertyByIndex(thisObject, exec, propertyName);
278 }
279
280 uint32_t JSDOMWindow::getEnumerableLength(ExecState* exec, JSObject* object)
281 {
282     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
283     // Only allow the window to enumerated by frames in the same origin.
284     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped()))
285         return 0;
286     return Base::getEnumerableLength(exec, thisObject);
287 }
288
289 void JSDOMWindow::getStructurePropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
290 {
291     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
292     // Only allow the window to enumerated by frames in the same origin.
293     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped()))
294         return;
295     Base::getStructurePropertyNames(thisObject, exec, propertyNames, mode);
296 }
297
298 void JSDOMWindow::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
299 {
300     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
301     // Only allow the window to enumerated by frames in the same origin.
302     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped()))
303         return;
304     Base::getGenericPropertyNames(thisObject, exec, propertyNames, mode);
305 }
306
307 void JSDOMWindow::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
308 {
309     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
310     // Only allow the window to enumerated by frames in the same origin.
311     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped()))
312         return;
313     Base::getPropertyNames(thisObject, exec, propertyNames, mode);
314 }
315
316 static void addCrossOriginWindowPropertyNames(ExecState& state, PropertyNameArray& propertyNames)
317 {
318     // https://html.spec.whatwg.org/#crossoriginproperties-(-o-)
319     static const Identifier* const properties[] = {
320         &state.propertyNames().blur, &state.propertyNames().close, &state.propertyNames().closed,
321         &state.propertyNames().focus, &state.propertyNames().frames, &state.propertyNames().length,
322         &state.propertyNames().location, &state.propertyNames().opener, &state.propertyNames().parent,
323         &state.propertyNames().postMessage, &state.propertyNames().self, &state.propertyNames().top,
324         &state.propertyNames().window
325     };
326     for (auto* property : properties)
327         propertyNames.add(*property);
328 }
329
330 void JSDOMWindow::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
331 {
332     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
333     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError)) {
334         if (mode.includeDontEnumProperties())
335             addCrossOriginWindowPropertyNames(*exec, propertyNames);
336         return;
337     }
338     Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
339 }
340
341 bool JSDOMWindow::defineOwnProperty(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, const JSC::PropertyDescriptor& descriptor, bool shouldThrow)
342 {
343     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
344     // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced.
345     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError))
346         return false;
347
348     // Don't allow shadowing location using accessor properties.
349     if (descriptor.isAccessorDescriptor() && propertyName == Identifier::fromString(exec, "location"))
350         return false;
351
352     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
353 }
354
355 JSValue JSDOMWindow::getPrototype(JSObject* object, ExecState* exec)
356 {
357     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
358     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError))
359         return jsNull();
360
361     return Base::getPrototype(object, exec);
362 }
363
364 bool JSDOMWindow::preventExtensions(JSObject*, ExecState* exec)
365 {
366     auto scope = DECLARE_THROW_SCOPE(exec->vm());
367
368     throwTypeError(exec, scope, ASCIILiteral("Cannot prevent extensions on this object"));
369     return false;
370 }
371
372 // Custom Attributes
373
374 void JSDOMWindow::setLocation(ExecState& state, JSValue value)
375 {
376     VM& vm = state.vm();
377     auto scope = DECLARE_THROW_SCOPE(vm);
378
379 #if ENABLE(DASHBOARD_SUPPORT)
380     // To avoid breaking old widgets, make "var location =" in a top-level frame create
381     // a property named "location" instead of performing a navigation (<rdar://problem/5688039>).
382     if (Frame* activeFrame = activeDOMWindow(&state).frame()) {
383         if (activeFrame->settings().usesDashboardBackwardCompatibilityMode() && !activeFrame->tree().parent()) {
384             if (BindingSecurity::shouldAllowAccessToDOMWindow(&state, wrapped()))
385                 putDirect(state.vm(), Identifier::fromString(&state, "location"), value);
386             return;
387         }
388     }
389 #endif
390
391     String locationString = value.toString(&state)->value(&state);
392     RETURN_IF_EXCEPTION(scope, void());
393
394     if (Location* location = wrapped().location())
395         location->setHref(activeDOMWindow(&state), firstDOMWindow(&state), locationString);
396 }
397
398 JSValue JSDOMWindow::event(ExecState& state) const
399 {
400     Event* event = currentEvent();
401     if (!event)
402         return jsUndefined();
403     return toJS(&state, const_cast<JSDOMWindow*>(this), event);
404 }
405
406 JSValue JSDOMWindow::image(ExecState& state) const
407 {
408     return createImageConstructor(state.vm(), *this);
409 }
410
411 // Custom functions
412
413 JSValue JSDOMWindow::open(ExecState& state)
414 {
415     VM& vm = state.vm();
416     auto scope = DECLARE_THROW_SCOPE(vm);
417
418     String urlString = convert<IDLNullable<IDLUSVString>>(state, state.argument(0));
419     RETURN_IF_EXCEPTION(scope, JSValue());
420     JSValue targetValue = state.argument(1);
421     AtomicString target = targetValue.isUndefinedOrNull() ? AtomicString("_blank", AtomicString::ConstructFromLiteral) : targetValue.toString(&state)->toAtomicString(&state);
422     RETURN_IF_EXCEPTION(scope, JSValue());
423     String windowFeaturesString = convert<IDLNullable<IDLDOMString>>(state, state.argument(2));
424     RETURN_IF_EXCEPTION(scope, JSValue());
425
426     RefPtr<DOMWindow> openedWindow = wrapped().open(urlString, target, windowFeaturesString, activeDOMWindow(&state), firstDOMWindow(&state));
427     if (!openedWindow)
428         return jsNull();
429     return toJS(&state, openedWindow.get());
430 }
431
432 class DialogHandler {
433 public:
434     explicit DialogHandler(ExecState& exec)
435         : m_exec(exec)
436     {
437     }
438
439     void dialogCreated(DOMWindow&);
440     JSValue returnValue() const;
441
442 private:
443     ExecState& m_exec;
444     RefPtr<Frame> m_frame;
445 };
446
447 inline void DialogHandler::dialogCreated(DOMWindow& dialog)
448 {
449     m_frame = dialog.frame();
450     
451     // FIXME: This looks like a leak between the normal world and an isolated
452     //        world if dialogArguments comes from an isolated world.
453     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec.vm()));
454     if (JSValue dialogArguments = m_exec.argument(1))
455         globalObject->putDirect(m_exec.vm(), Identifier::fromString(&m_exec, "dialogArguments"), dialogArguments);
456 }
457
458 inline JSValue DialogHandler::returnValue() const
459 {
460     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec.vm()));
461     if (!globalObject)
462         return jsUndefined();
463     Identifier identifier = Identifier::fromString(&m_exec, "returnValue");
464     PropertySlot slot(globalObject, PropertySlot::InternalMethodType::Get);
465     if (!JSGlobalObject::getOwnPropertySlot(globalObject, &m_exec, identifier, slot))
466         return jsUndefined();
467     return slot.getValue(&m_exec, identifier);
468 }
469
470 JSValue JSDOMWindow::showModalDialog(ExecState& state)
471 {
472     VM& vm = state.vm();
473     auto scope = DECLARE_THROW_SCOPE(vm);
474
475     if (UNLIKELY(state.argumentCount() < 1))
476         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
477
478     String urlString = convert<IDLNullable<IDLDOMString>>(state, state.argument(0));
479     RETURN_IF_EXCEPTION(scope, JSValue());
480     String dialogFeaturesString = convert<IDLNullable<IDLDOMString>>(state, state.argument(2));
481     RETURN_IF_EXCEPTION(scope, JSValue());
482
483     DialogHandler handler(state);
484
485     wrapped().showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(&state), firstDOMWindow(&state), [&handler](DOMWindow& dialog) {
486         handler.dialogCreated(dialog);
487     });
488
489     return handler.returnValue();
490 }
491
492 static JSValue handlePostMessage(DOMWindow& impl, ExecState& state)
493 {
494     VM& vm = state.vm();
495     auto scope = DECLARE_THROW_SCOPE(vm);
496
497     if (UNLIKELY(state.argumentCount() < 2))
498         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
499
500     Vector<RefPtr<MessagePort>> messagePorts;
501     Vector<RefPtr<JSC::ArrayBuffer>> arrayBuffers;
502
503     // This function has variable arguments and can be:
504     // Per current spec:
505     //   postMessage(message, targetOrigin)
506     //   postMessage(message, targetOrigin, {sequence of transferrables})
507     // Legacy non-standard implementations in webkit allowed:
508     //   postMessage(message, {sequence of transferrables}, targetOrigin);
509     int targetOriginArgIndex = 1;
510     if (state.argumentCount() > 2) {
511         int transferablesArgIndex = 2;
512         if (state.uncheckedArgument(2).isString()) {
513             targetOriginArgIndex = 2;
514             transferablesArgIndex = 1;
515         }
516         extractTransferables(state, state.argument(transferablesArgIndex), messagePorts, arrayBuffers);
517     }
518     RETURN_IF_EXCEPTION(scope, JSValue());
519
520     auto message = SerializedScriptValue::create(state, state.uncheckedArgument(0), messagePorts, WTFMove(arrayBuffers));
521     RETURN_IF_EXCEPTION(scope, JSValue());
522
523     String targetOrigin = convert<IDLNullable<IDLUSVString>>(state, state.uncheckedArgument(targetOriginArgIndex));
524     RETURN_IF_EXCEPTION(scope, JSValue());
525
526     propagateException(state, scope, impl.postMessage(message.releaseNonNull(), WTFMove(messagePorts), targetOrigin, callerDOMWindow(&state)));
527
528     return jsUndefined();
529 }
530
531 JSValue JSDOMWindow::postMessage(ExecState& state)
532 {
533     return handlePostMessage(wrapped(), state);
534 }
535
536 JSValue JSDOMWindow::setTimeout(ExecState& state)
537 {
538     VM& vm = state.vm();
539     auto scope = DECLARE_THROW_SCOPE(vm);
540
541     if (UNLIKELY(state.argumentCount() < 1))
542         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
543
544     auto* contentSecurityPolicy = wrapped().document() ? wrapped().document()->contentSecurityPolicy() : nullptr;
545     auto action = ScheduledAction::create(&state, globalObject()->world(), contentSecurityPolicy);
546     RETURN_IF_EXCEPTION(scope, JSValue());
547     if (!action)
548         return jsNumber(0);
549
550     int delay = state.argument(1).toInt32(&state);
551     return toJS<IDLLong>(state, scope, wrapped().setTimeout(WTFMove(action), delay));
552 }
553
554 JSValue JSDOMWindow::setInterval(ExecState& state)
555 {
556     VM& vm = state.vm();
557     auto scope = DECLARE_THROW_SCOPE(vm);
558
559     if (UNLIKELY(state.argumentCount() < 1))
560         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
561
562     auto* contentSecurityPolicy = wrapped().document() ? wrapped().document()->contentSecurityPolicy() : nullptr;
563     auto action = ScheduledAction::create(&state, globalObject()->world(), contentSecurityPolicy);
564     RETURN_IF_EXCEPTION(scope, JSValue());
565     if (!action)
566         return jsNumber(0);
567
568     int delay = state.argument(1).toInt32(&state);
569     return toJS<IDLLong>(state, scope, wrapped().setInterval(WTFMove(action), delay));
570 }
571
572 DOMWindow* JSDOMWindow::toWrapped(JSValue value)
573 {
574     if (!value.isObject())
575         return nullptr;
576     JSObject* object = asObject(value);
577     if (object->inherits(JSDOMWindow::info()))
578         return &jsCast<JSDOMWindow*>(object)->wrapped();
579     if (object->inherits(JSDOMWindowShell::info()))
580         return &jsCast<JSDOMWindowShell*>(object)->wrapped();
581     return nullptr;
582 }
583
584 } // namespace WebCore