ServiceWorkers API should reject promises when calling objects inside detached frames
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMGlobalObject.cpp
1 /*
2  * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26
27 #include "config.h"
28 #include "JSDOMGlobalObject.h"
29
30 #include "DOMWindow.h"
31 #include "Document.h"
32 #include "JSDOMPromiseDeferred.h"
33 #include "JSDOMWindow.h"
34 #include "JSEventListener.h"
35 #include "JSMediaStream.h"
36 #include "JSMediaStreamTrack.h"
37 #include "JSRTCIceCandidate.h"
38 #include "JSRTCSessionDescription.h"
39 #include "JSReadableStream.h"
40 #include "JSReadableStreamPrivateConstructors.h"
41 #include "JSWorkerGlobalScope.h"
42 #include "RuntimeEnabledFeatures.h"
43 #include "StructuredClone.h"
44 #include "WebCoreJSClientData.h"
45 #include "WorkerGlobalScope.h"
46 #include <builtins/BuiltinNames.h>
47
48
49 namespace WebCore {
50 using namespace JSC;
51
52 EncodedJSValue JSC_HOST_CALL makeThisTypeErrorForBuiltins(ExecState*);
53 EncodedJSValue JSC_HOST_CALL makeGetterTypeErrorForBuiltins(ExecState*);
54 EncodedJSValue JSC_HOST_CALL isWebRTCLegacyAPIEnabled(ExecState*);
55 EncodedJSValue JSC_HOST_CALL isReadableByteStreamAPIEnabled(ExecState*);
56
57 const ClassInfo JSDOMGlobalObject::s_info = { "DOMGlobalObject", &JSGlobalObject::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDOMGlobalObject) };
58
59 JSDOMGlobalObject::JSDOMGlobalObject(VM& vm, Structure* structure, Ref<DOMWrapperWorld>&& world, const GlobalObjectMethodTable* globalObjectMethodTable)
60     : JSGlobalObject(vm, structure, globalObjectMethodTable)
61     , m_currentEvent(0)
62     , m_world(WTFMove(world))
63     , m_worldIsNormal(m_world->isNormal())
64     , m_builtinInternalFunctions(vm)
65 {
66 }
67
68 JSDOMGlobalObject::~JSDOMGlobalObject() = default;
69
70 void JSDOMGlobalObject::destroy(JSCell* cell)
71 {
72     static_cast<JSDOMGlobalObject*>(cell)->JSDOMGlobalObject::~JSDOMGlobalObject();
73 }
74
75 EncodedJSValue JSC_HOST_CALL makeThisTypeErrorForBuiltins(ExecState* execState)
76 {
77     ASSERT(execState);
78     ASSERT(execState->argumentCount() == 2);
79     VM& vm = execState->vm();
80     auto scope = DECLARE_CATCH_SCOPE(vm);
81
82     auto interfaceName = execState->uncheckedArgument(0).getString(execState);
83     scope.assertNoException();
84     auto functionName = execState->uncheckedArgument(1).getString(execState);
85     scope.assertNoException();
86     return JSValue::encode(createTypeError(execState, makeThisTypeErrorMessage(interfaceName.utf8().data(), functionName.utf8().data())));
87 }
88
89 EncodedJSValue JSC_HOST_CALL makeGetterTypeErrorForBuiltins(ExecState* execState)
90 {
91     ASSERT(execState);
92     ASSERT(execState->argumentCount() == 2);
93     VM& vm = execState->vm();
94     auto scope = DECLARE_CATCH_SCOPE(vm);
95
96     auto interfaceName = execState->uncheckedArgument(0).getString(execState);
97     scope.assertNoException();
98     auto attributeName = execState->uncheckedArgument(1).getString(execState);
99     scope.assertNoException();
100     return JSValue::encode(createTypeError(execState, makeGetterTypeErrorMessage(interfaceName.utf8().data(), attributeName.utf8().data())));
101 }
102
103 #if ENABLE(WEB_RTC)
104 EncodedJSValue JSC_HOST_CALL isWebRTCLegacyAPIEnabled(ExecState*)
105 {
106     return JSValue::encode(jsBoolean(RuntimeEnabledFeatures::sharedFeatures().webRTCLegacyAPIEnabled()));
107 }
108 #endif
109
110 #if ENABLE(STREAMS_API)
111 EncodedJSValue JSC_HOST_CALL isReadableByteStreamAPIEnabled(ExecState*)
112 {
113     return JSValue::encode(jsBoolean(RuntimeEnabledFeatures::sharedFeatures().readableByteStreamAPIEnabled()));
114 }
115 #endif
116
117 void JSDOMGlobalObject::addBuiltinGlobals(VM& vm)
118 {
119     m_builtinInternalFunctions.initialize(*this);
120
121 #if ENABLE(STREAMS_API)
122     JSObject* privateReadableStreamDefaultControllerConstructor = createReadableStreamDefaultControllerPrivateConstructor(vm, *this);
123     JSObject* privateReadableByteStreamControllerConstructor = createReadableByteStreamControllerPrivateConstructor(vm, *this);
124     JSObject* privateReadableStreamBYOBRequestConstructor = createReadableStreamBYOBRequestPrivateConstructor(vm, *this);
125     JSObject* privateReadableStreamDefaultReaderConstructor = createReadableStreamDefaultReaderPrivateConstructor(vm, *this);
126     JSObject* privateReadableStreamBYOBReaderConstructor = createReadableStreamBYOBReaderPrivateConstructor(vm, *this);
127
128     ASSERT(!constructors(NoLockingNecessary).get(privateReadableStreamDefaultControllerConstructor->info()).get());
129     ASSERT(!constructors(NoLockingNecessary).get(privateReadableByteStreamControllerConstructor->info()).get());
130     ASSERT(!constructors(NoLockingNecessary).get(privateReadableStreamBYOBRequestConstructor->info()).get());
131     ASSERT(!constructors(NoLockingNecessary).get(privateReadableStreamDefaultReaderConstructor->info()).get());
132     ASSERT(!constructors(NoLockingNecessary).get(privateReadableStreamBYOBReaderConstructor->info()).get());
133     JSC::WriteBarrier<JSC::JSObject> temp;
134     {
135         auto locker = lockDuringMarking(vm.heap, m_gcLock);
136         constructors(locker).add(privateReadableStreamDefaultControllerConstructor->info(), temp).iterator->value.set(vm, this, privateReadableStreamDefaultControllerConstructor);
137         constructors(locker).add(privateReadableByteStreamControllerConstructor->info(), temp).iterator->value.set(vm, this, privateReadableByteStreamControllerConstructor);
138         constructors(locker).add(privateReadableStreamBYOBRequestConstructor->info(), temp).iterator->value.set(vm, this, privateReadableStreamBYOBRequestConstructor);
139         constructors(locker).add(privateReadableStreamDefaultReaderConstructor->info(), temp).iterator->value.set(vm, this, privateReadableStreamDefaultReaderConstructor);
140         constructors(locker).add(privateReadableStreamBYOBReaderConstructor->info(), temp).iterator->value.set(vm, this, privateReadableStreamBYOBReaderConstructor);
141     }
142 #endif
143     JSVMClientData& clientData = *static_cast<JSVMClientData*>(vm.clientData);
144     JSDOMGlobalObject::GlobalPropertyInfo staticGlobals[] = {
145         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().makeThisTypeErrorPrivateName(),
146             JSFunction::create(vm, this, 2, String(), makeThisTypeErrorForBuiltins), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
147         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().makeGetterTypeErrorPrivateName(),
148             JSFunction::create(vm, this, 2, String(), makeGetterTypeErrorForBuiltins), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
149         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().cloneArrayBufferPrivateName(),
150             JSFunction::create(vm, this, 3, String(), cloneArrayBuffer), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
151         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().structuredCloneArrayBufferPrivateName(),
152             JSFunction::create(vm, this, 1, String(), structuredCloneArrayBuffer), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
153         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().structuredCloneArrayBufferViewPrivateName(),
154             JSFunction::create(vm, this, 1, String(), structuredCloneArrayBufferView), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
155         JSDOMGlobalObject::GlobalPropertyInfo(vm.propertyNames->builtinNames().ArrayBufferPrivateName(), getDirect(vm, vm.propertyNames->ArrayBuffer), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
156 #if ENABLE(STREAMS_API)
157         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamClosedPrivateName(), jsNumber(1), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
158         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamClosingPrivateName(), jsNumber(2), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
159         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamErroredPrivateName(), jsNumber(3), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
160         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamReadablePrivateName(), jsNumber(4), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
161         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamWaitingPrivateName(), jsNumber(5), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
162         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamWritablePrivateName(), jsNumber(6), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
163         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().ReadableStreamDefaultControllerPrivateName(), privateReadableStreamDefaultControllerConstructor, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
164         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().ReadableByteStreamControllerPrivateName(), privateReadableByteStreamControllerConstructor, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
165         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().ReadableStreamBYOBRequestPrivateName(), privateReadableStreamBYOBRequestConstructor, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
166         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().ReadableStreamDefaultReaderPrivateName(), privateReadableStreamDefaultReaderConstructor, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
167         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().ReadableStreamBYOBReaderPrivateName(), privateReadableStreamBYOBReaderConstructor, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
168         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().readableByteStreamAPIEnabledPrivateName(), JSFunction::create(vm, this, 0, String(), isReadableByteStreamAPIEnabled), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
169 #endif
170 #if ENABLE(WEB_RTC)
171         JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().webRTCLegacyAPIEnabledPrivateName(), JSFunction::create(vm, this, 0, String(), isWebRTCLegacyAPIEnabled), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
172 #endif
173     };
174     addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
175 }
176
177 void JSDOMGlobalObject::finishCreation(VM& vm)
178 {
179     Base::finishCreation(vm);
180     ASSERT(inherits(vm, info()));
181
182     addBuiltinGlobals(vm);
183
184     RELEASE_ASSERT(classInfo());
185 }
186
187 void JSDOMGlobalObject::finishCreation(VM& vm, JSObject* thisValue)
188 {
189     Base::finishCreation(vm, thisValue);
190     ASSERT(inherits(vm, info()));
191
192     addBuiltinGlobals(vm);
193
194     RELEASE_ASSERT(classInfo());
195 }
196
197 ScriptExecutionContext* JSDOMGlobalObject::scriptExecutionContext() const
198 {
199     if (inherits(vm(), JSDOMWindowBase::info()))
200         return jsCast<const JSDOMWindowBase*>(this)->scriptExecutionContext();
201     if (inherits(vm(), JSWorkerGlobalScopeBase::info()))
202         return jsCast<const JSWorkerGlobalScopeBase*>(this)->scriptExecutionContext();
203     dataLog("Unexpected global object: ", JSValue(this), "\n");
204     RELEASE_ASSERT_NOT_REACHED();
205     return 0;
206 }
207
208 void JSDOMGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
209 {
210     JSDOMGlobalObject* thisObject = jsCast<JSDOMGlobalObject*>(cell);
211     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
212     Base::visitChildren(thisObject, visitor);
213
214     {
215         auto locker = holdLock(thisObject->m_gcLock);
216
217         for (auto& structure : thisObject->structures(locker).values())
218             visitor.append(structure);
219
220         for (auto& constructor : thisObject->constructors(locker).values())
221             visitor.append(constructor);
222
223         for (auto& guarded : thisObject->guardedObjects(locker))
224             guarded->visitAggregate(visitor);
225     }
226
227     thisObject->m_builtinInternalFunctions.visit(visitor);
228 }
229
230 void JSDOMGlobalObject::setCurrentEvent(Event* currentEvent)
231 {
232     m_currentEvent = currentEvent;
233 }
234
235 Event* JSDOMGlobalObject::currentEvent() const
236 {
237     return m_currentEvent;
238 }
239
240 JSDOMGlobalObject* toJSDOMGlobalObject(Document* document, JSC::ExecState* exec)
241 {
242     return toJSDOMWindow(document->frame(), currentWorld(exec));
243 }
244
245 JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext* scriptExecutionContext, JSC::ExecState* exec)
246 {
247     if (is<Document>(*scriptExecutionContext))
248         return toJSDOMGlobalObject(downcast<Document>(scriptExecutionContext), exec);
249
250     if (is<WorkerGlobalScope>(*scriptExecutionContext))
251         return downcast<WorkerGlobalScope>(*scriptExecutionContext).script()->workerGlobalScopeWrapper();
252
253     ASSERT_NOT_REACHED();
254     return nullptr;
255 }
256
257 JSDOMGlobalObject* toJSDOMGlobalObject(Document* document, DOMWrapperWorld& world)
258 {
259     return toJSDOMWindow(document->frame(), world);
260 }
261
262 JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext* scriptExecutionContext, DOMWrapperWorld& world)
263 {
264     if (is<Document>(*scriptExecutionContext))
265         return toJSDOMGlobalObject(downcast<Document>(scriptExecutionContext), world);
266
267     if (is<WorkerGlobalScope>(*scriptExecutionContext))
268         return downcast<WorkerGlobalScope>(*scriptExecutionContext).script()->workerGlobalScopeWrapper();
269
270     ASSERT_NOT_REACHED();
271     return nullptr;
272 }
273
274 JSDOMGlobalObject& callerGlobalObject(ExecState& state)
275 {
276     class GetCallerGlobalObjectFunctor {
277     public:
278         GetCallerGlobalObjectFunctor() = default;
279
280         StackVisitor::Status operator()(StackVisitor& visitor) const
281         {
282             if (!m_hasSkippedFirstFrame) {
283                 m_hasSkippedFirstFrame = true;
284                 return StackVisitor::Continue;
285             }
286
287             if (auto* codeBlock = visitor->codeBlock())
288                 m_globalObject = codeBlock->globalObject();
289             else {
290                 ASSERT(visitor->callee().rawPtr());
291                 // FIXME: Callee is not an object if the caller is Web Assembly.
292                 // Figure out what to do here. We can probably get the global object
293                 // from the top-most Wasm Instance. https://bugs.webkit.org/show_bug.cgi?id=165721
294                 if (visitor->callee().isCell() && visitor->callee().asCell()->isObject())
295                     m_globalObject = jsCast<JSObject*>(visitor->callee().asCell())->globalObject();
296             }
297             return StackVisitor::Done;
298         }
299
300         JSGlobalObject* globalObject() const { return m_globalObject; }
301
302     private:
303         mutable bool m_hasSkippedFirstFrame { false };
304         mutable JSGlobalObject* m_globalObject { nullptr };
305     };
306
307     GetCallerGlobalObjectFunctor iter;
308     state.iterate(iter);
309     return *jsCast<JSDOMGlobalObject*>(iter.globalObject() ? iter.globalObject() : state.vmEntryGlobalObject());
310 }
311
312 } // namespace WebCore