1 | /* |
2 | * Copyright (C) 2000 Harri Porten (porten@kde.org) |
3 | * Copyright (C) 2006 Jon Shier (jshier@iastate.edu) |
4 | * Copyright (C) 2003-2017 Apple Inc. All rights reseved. |
5 | * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) |
6 | * Copyright (c) 2015 Canon Inc. All rights reserved. |
7 | * |
8 | * This library is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Lesser General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2 of the License, or (at your option) any later version. |
12 | * |
13 | * This library is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Lesser General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Lesser General Public |
19 | * License along with this library; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 |
21 | * USA |
22 | */ |
23 | |
24 | #include "config.h" |
25 | #include "JSDOMWindowBase.h" |
26 | |
27 | #include "ActiveDOMCallbackMicrotask.h" |
28 | #include "Chrome.h" |
29 | #include "CommonVM.h" |
30 | #include "DOMWindow.h" |
31 | #include "Document.h" |
32 | #include "FetchResponse.h" |
33 | #include "Frame.h" |
34 | #include "InspectorController.h" |
35 | #include "JSDOMBindingSecurity.h" |
36 | #include "JSDOMGlobalObjectTask.h" |
37 | #include "JSDOMWindowCustom.h" |
38 | #include "JSFetchResponse.h" |
39 | #include "JSMicrotaskCallback.h" |
40 | #include "JSNode.h" |
41 | #include "Logging.h" |
42 | #include "Page.h" |
43 | #include "RejectedPromiseTracker.h" |
44 | #include "RuntimeApplicationChecks.h" |
45 | #include "ScriptController.h" |
46 | #include "ScriptModuleLoader.h" |
47 | #include "SecurityOrigin.h" |
48 | #include "Settings.h" |
49 | #include "WebCoreJSClientData.h" |
50 | #include <JavaScriptCore/CodeBlock.h> |
51 | #include <JavaScriptCore/JSInternalPromise.h> |
52 | #include <JavaScriptCore/JSInternalPromiseDeferred.h> |
53 | #include <JavaScriptCore/Microtask.h> |
54 | #include <JavaScriptCore/PromiseDeferredTimer.h> |
55 | #include <JavaScriptCore/StrongInlines.h> |
56 | #include <JavaScriptCore/WebAssemblyPrototype.h> |
57 | #include <wtf/Language.h> |
58 | #include <wtf/MainThread.h> |
59 | |
60 | #if PLATFORM(IOS_FAMILY) |
61 | #include "ChromeClient.h" |
62 | #endif |
63 | |
64 | |
65 | namespace WebCore { |
66 | using namespace JSC; |
67 | |
68 | const ClassInfo JSDOMWindowBase::s_info = { "Window" , &JSDOMGlobalObject::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDOMWindowBase) }; |
69 | |
70 | const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = { |
71 | &supportsRichSourceInfo, |
72 | &shouldInterruptScript, |
73 | &javaScriptRuntimeFlags, |
74 | &queueTaskToEventLoop, |
75 | &shouldInterruptScriptBeforeTimeout, |
76 | &moduleLoaderImportModule, |
77 | &moduleLoaderResolve, |
78 | &moduleLoaderFetch, |
79 | &moduleLoaderCreateImportMetaProperties, |
80 | &moduleLoaderEvaluate, |
81 | &promiseRejectionTracker, |
82 | &defaultLanguage, |
83 | #if ENABLE(WEBASSEMBLY) |
84 | &compileStreaming, |
85 | &instantiateStreaming, |
86 | #else |
87 | nullptr, |
88 | nullptr, |
89 | #endif |
90 | }; |
91 | |
92 | JSDOMWindowBase::JSDOMWindowBase(VM& vm, Structure* structure, RefPtr<DOMWindow>&& window, JSWindowProxy* proxy) |
93 | : JSDOMGlobalObject(vm, structure, proxy->world(), &s_globalObjectMethodTable) |
94 | , m_windowCloseWatchpoints((window && window->frame()) ? IsWatched : IsInvalidated) |
95 | , m_wrapped(WTFMove(window)) |
96 | , m_proxy(proxy) |
97 | { |
98 | } |
99 | |
100 | void JSDOMWindowBase::finishCreation(VM& vm, JSWindowProxy* proxy) |
101 | { |
102 | Base::finishCreation(vm, proxy); |
103 | ASSERT(inherits(vm, info())); |
104 | |
105 | auto& builtinNames = static_cast<JSVMClientData*>(vm.clientData)->builtinNames(); |
106 | |
107 | GlobalPropertyInfo staticGlobals[] = { |
108 | GlobalPropertyInfo(builtinNames.documentPublicName(), jsNull(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), |
109 | GlobalPropertyInfo(builtinNames.windowPublicName(), m_proxy, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), |
110 | }; |
111 | |
112 | addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals)); |
113 | |
114 | if (m_wrapped && m_wrapped->frame() && m_wrapped->frame()->settings().needsSiteSpecificQuirks()) |
115 | setNeedsSiteSpecificQuirks(true); |
116 | } |
117 | |
118 | void JSDOMWindowBase::destroy(JSCell* cell) |
119 | { |
120 | static_cast<JSDOMWindowBase*>(cell)->JSDOMWindowBase::~JSDOMWindowBase(); |
121 | } |
122 | |
123 | void JSDOMWindowBase::updateDocument() |
124 | { |
125 | // Since "document" property is defined as { configurable: false, writable: false, enumerable: true }, |
126 | // users cannot change its attributes further. |
127 | // Reaching here, the attributes of "document" property should be never changed. |
128 | ASSERT(m_wrapped->document()); |
129 | ExecState* exec = globalExec(); |
130 | bool shouldThrowReadOnlyError = false; |
131 | bool ignoreReadOnlyErrors = true; |
132 | bool putResult = false; |
133 | symbolTablePutTouchWatchpointSet(this, exec, static_cast<JSVMClientData*>(exec->vm().clientData)->builtinNames().documentPublicName(), toJS(exec, this, m_wrapped->document()), shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult); |
134 | } |
135 | |
136 | ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const |
137 | { |
138 | return m_wrapped->document(); |
139 | } |
140 | |
141 | void JSDOMWindowBase::printErrorMessage(const String& message) const |
142 | { |
143 | printErrorMessageForFrame(wrapped().frame(), message); |
144 | } |
145 | |
146 | bool JSDOMWindowBase::supportsRichSourceInfo(const JSGlobalObject* object) |
147 | { |
148 | const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); |
149 | Frame* frame = thisObject->wrapped().frame(); |
150 | if (!frame) |
151 | return false; |
152 | |
153 | Page* page = frame->page(); |
154 | if (!page) |
155 | return false; |
156 | |
157 | bool enabled = page->inspectorController().enabled(); |
158 | ASSERT(enabled || !thisObject->debugger()); |
159 | return enabled; |
160 | } |
161 | |
162 | static inline bool shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(Page* page) |
163 | { |
164 | // See <rdar://problem/5479443>. We don't think that page can ever be NULL |
165 | // in this case, but if it is, we've gotten into a state where we may have |
166 | // hung the UI, with no way to ask the client whether to cancel execution. |
167 | // For now, our solution is just to cancel execution no matter what, |
168 | // ensuring that we never hang. We might want to consider other solutions |
169 | // if we discover problems with this one. |
170 | ASSERT(page); |
171 | return !page; |
172 | } |
173 | |
174 | bool JSDOMWindowBase::shouldInterruptScript(const JSGlobalObject* object) |
175 | { |
176 | const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); |
177 | ASSERT(thisObject->wrapped().frame()); |
178 | Page* page = thisObject->wrapped().frame()->page(); |
179 | return shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page); |
180 | } |
181 | |
182 | bool JSDOMWindowBase::shouldInterruptScriptBeforeTimeout(const JSGlobalObject* object) |
183 | { |
184 | const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); |
185 | ASSERT(thisObject->wrapped().frame()); |
186 | Page* page = thisObject->wrapped().frame()->page(); |
187 | |
188 | if (shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page)) |
189 | return true; |
190 | |
191 | #if PLATFORM(IOS_FAMILY) |
192 | if (page->chrome().client().isStopping()) |
193 | return true; |
194 | #endif |
195 | |
196 | return JSGlobalObject::shouldInterruptScriptBeforeTimeout(object); |
197 | } |
198 | |
199 | RuntimeFlags JSDOMWindowBase::javaScriptRuntimeFlags(const JSGlobalObject* object) |
200 | { |
201 | const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); |
202 | Frame* frame = thisObject->wrapped().frame(); |
203 | if (!frame) |
204 | return RuntimeFlags(); |
205 | return frame->settings().javaScriptRuntimeFlags(); |
206 | } |
207 | |
208 | void JSDOMWindowBase::queueTaskToEventLoop(JSGlobalObject& object, Ref<JSC::Microtask>&& task) |
209 | { |
210 | JSDOMWindowBase& thisObject = static_cast<JSDOMWindowBase&>(object); |
211 | |
212 | auto callback = JSMicrotaskCallback::create(thisObject, WTFMove(task)); |
213 | auto microtask = std::make_unique<ActiveDOMCallbackMicrotask>(MicrotaskQueue::mainThreadQueue(), *thisObject.scriptExecutionContext(), [callback = WTFMove(callback)]() mutable { |
214 | callback->call(); |
215 | }); |
216 | |
217 | MicrotaskQueue::mainThreadQueue().append(WTFMove(microtask)); |
218 | } |
219 | |
220 | void JSDOMWindowBase::willRemoveFromWindowProxy() |
221 | { |
222 | setCurrentEvent(0); |
223 | } |
224 | |
225 | JSWindowProxy* JSDOMWindowBase::proxy() const |
226 | { |
227 | return m_proxy; |
228 | } |
229 | |
230 | JSValue toJS(ExecState* state, DOMWindow& domWindow) |
231 | { |
232 | auto* frame = domWindow.frame(); |
233 | if (!frame) |
234 | return jsNull(); |
235 | return toJS(state, frame->windowProxy()); |
236 | } |
237 | |
238 | JSDOMWindow* toJSDOMWindow(Frame& frame, DOMWrapperWorld& world) |
239 | { |
240 | return frame.script().globalObject(world); |
241 | } |
242 | |
243 | JSDOMWindow* toJSDOMWindow(JSC::VM& vm, JSValue value) |
244 | { |
245 | if (!value.isObject()) |
246 | return nullptr; |
247 | |
248 | while (!value.isNull()) { |
249 | JSObject* object = asObject(value); |
250 | const ClassInfo* classInfo = object->classInfo(vm); |
251 | if (classInfo == JSDOMWindow::info()) |
252 | return jsCast<JSDOMWindow*>(object); |
253 | if (classInfo == JSWindowProxy::info()) |
254 | return jsDynamicCast<JSDOMWindow*>(vm, jsCast<JSWindowProxy*>(object)->window()); |
255 | value = object->getPrototypeDirect(vm); |
256 | } |
257 | return nullptr; |
258 | } |
259 | |
260 | DOMWindow& incumbentDOMWindow(ExecState& state) |
261 | { |
262 | return asJSDOMWindow(&callerGlobalObject(state))->wrapped(); |
263 | } |
264 | |
265 | DOMWindow& activeDOMWindow(ExecState& state) |
266 | { |
267 | return asJSDOMWindow(state.lexicalGlobalObject())->wrapped(); |
268 | } |
269 | |
270 | DOMWindow& firstDOMWindow(ExecState& state) |
271 | { |
272 | VM& vm = state.vm(); |
273 | return asJSDOMWindow(vm.vmEntryGlobalObject(&state))->wrapped(); |
274 | } |
275 | |
276 | Document* responsibleDocument(ExecState& state) |
277 | { |
278 | CallerFunctor functor; |
279 | state.iterate(functor); |
280 | auto* callerFrame = functor.callerFrame(); |
281 | if (!callerFrame) |
282 | return nullptr; |
283 | return asJSDOMWindow(callerFrame->lexicalGlobalObject())->wrapped().document(); |
284 | } |
285 | |
286 | void JSDOMWindowBase::fireFrameClearedWatchpointsForWindow(DOMWindow* window) |
287 | { |
288 | JSC::VM& vm = commonVM(); |
289 | JSVMClientData* clientData = static_cast<JSVMClientData*>(vm.clientData); |
290 | Vector<Ref<DOMWrapperWorld>> wrapperWorlds; |
291 | clientData->getAllWorlds(wrapperWorlds); |
292 | for (unsigned i = 0; i < wrapperWorlds.size(); ++i) { |
293 | auto& wrappers = wrapperWorlds[i]->wrappers(); |
294 | auto result = wrappers.find(window); |
295 | if (result == wrappers.end()) |
296 | continue; |
297 | JSC::JSObject* wrapper = result->value.get(); |
298 | if (!wrapper) |
299 | continue; |
300 | JSDOMWindowBase* jsWindow = JSC::jsCast<JSDOMWindowBase*>(wrapper); |
301 | jsWindow->m_windowCloseWatchpoints.fireAll(vm, "Frame cleared" ); |
302 | } |
303 | } |
304 | |
305 | JSC::Identifier JSDOMWindowBase::moduleLoaderResolve(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleName, JSC::JSValue importerModuleKey, JSC::JSValue scriptFetcher) |
306 | { |
307 | JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject); |
308 | if (RefPtr<Document> document = thisObject->wrapped().document()) |
309 | return document->moduleLoader().resolve(globalObject, exec, moduleLoader, moduleName, importerModuleKey, scriptFetcher); |
310 | return { }; |
311 | } |
312 | |
313 | JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderFetch(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleKey, JSC::JSValue parameters, JSC::JSValue scriptFetcher) |
314 | { |
315 | VM& vm = exec->vm(); |
316 | auto scope = DECLARE_THROW_SCOPE(vm); |
317 | JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject); |
318 | if (RefPtr<Document> document = thisObject->wrapped().document()) |
319 | RELEASE_AND_RETURN(scope, document->moduleLoader().fetch(globalObject, exec, moduleLoader, moduleKey, parameters, scriptFetcher)); |
320 | JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::tryCreate(exec, globalObject); |
321 | RETURN_IF_EXCEPTION(scope, nullptr); |
322 | RELEASE_AND_RETURN(scope, deferred->reject(exec, jsUndefined())); |
323 | } |
324 | |
325 | JSC::JSValue JSDOMWindowBase::moduleLoaderEvaluate(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleKey, JSC::JSValue moduleRecord, JSC::JSValue scriptFetcher) |
326 | { |
327 | JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject); |
328 | if (RefPtr<Document> document = thisObject->wrapped().document()) |
329 | return document->moduleLoader().evaluate(globalObject, exec, moduleLoader, moduleKey, moduleRecord, scriptFetcher); |
330 | return JSC::jsUndefined(); |
331 | } |
332 | |
333 | JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderImportModule(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSString* moduleName, JSC::JSValue parameters, const JSC::SourceOrigin& sourceOrigin) |
334 | { |
335 | VM& vm = exec->vm(); |
336 | auto scope = DECLARE_THROW_SCOPE(vm); |
337 | JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject); |
338 | if (RefPtr<Document> document = thisObject->wrapped().document()) |
339 | RELEASE_AND_RETURN(scope, document->moduleLoader().importModule(globalObject, exec, moduleLoader, moduleName, parameters, sourceOrigin)); |
340 | JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::tryCreate(exec, globalObject); |
341 | RETURN_IF_EXCEPTION(scope, nullptr); |
342 | RELEASE_AND_RETURN(scope, deferred->reject(exec, jsUndefined())); |
343 | } |
344 | |
345 | JSC::JSObject* JSDOMWindowBase::moduleLoaderCreateImportMetaProperties(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleKey, JSC::JSModuleRecord* moduleRecord, JSC::JSValue scriptFetcher) |
346 | { |
347 | JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject); |
348 | if (RefPtr<Document> document = thisObject->wrapped().document()) |
349 | return document->moduleLoader().createImportMetaProperties(globalObject, exec, moduleLoader, moduleKey, moduleRecord, scriptFetcher); |
350 | return constructEmptyObject(exec, globalObject->nullPrototypeObjectStructure()); |
351 | } |
352 | |
353 | #if ENABLE(WEBASSEMBLY) |
354 | static Optional<Vector<uint8_t>> tryAllocate(JSC::ExecState* exec, JSC::JSPromiseDeferred* promise, const char* data, size_t byteSize) |
355 | { |
356 | Vector<uint8_t> arrayBuffer; |
357 | if (!arrayBuffer.tryReserveCapacity(byteSize)) { |
358 | promise->reject(exec, createOutOfMemoryError(exec)); |
359 | return WTF::nullopt; |
360 | } |
361 | |
362 | arrayBuffer.grow(byteSize); |
363 | memcpy(arrayBuffer.data(), data, byteSize); |
364 | |
365 | return arrayBuffer; |
366 | } |
367 | |
368 | static bool isResponseCorrect(JSC::ExecState* exec, FetchResponse* inputResponse, JSC::JSPromiseDeferred* promise) |
369 | { |
370 | bool = inputResponse->type() == ResourceResponse::Type::Basic || inputResponse->type() == ResourceResponse::Type::Cors || inputResponse->type() == ResourceResponse::Type::Default; |
371 | |
372 | if (!isResponseCorsSameOrigin) { |
373 | promise->reject(exec, createTypeError(exec, "Response is not CORS-same-origin"_s )); |
374 | return false; |
375 | } |
376 | |
377 | if (!inputResponse->ok()) { |
378 | promise->reject(exec, createTypeError(exec, "Response has not returned OK status"_s )); |
379 | return false; |
380 | } |
381 | |
382 | auto contentType = inputResponse->headers().fastGet(HTTPHeaderName::ContentType); |
383 | if (!equalLettersIgnoringASCIICase(contentType, "application/wasm" )) { |
384 | promise->reject(exec, createTypeError(exec, "Unexpected response MIME type. Expected 'application/wasm'"_s )); |
385 | return false; |
386 | } |
387 | |
388 | return true; |
389 | } |
390 | |
391 | static void handleResponseOnStreamingAction(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, FetchResponse* inputResponse, JSC::JSPromiseDeferred* promise, Function<void(JSC::ExecState* exec, const char* data, size_t byteSize)>&& actionCallback) |
392 | { |
393 | if (!isResponseCorrect(exec, inputResponse, promise)) |
394 | return; |
395 | |
396 | if (inputResponse->isBodyReceivedByChunk()) { |
397 | inputResponse->consumeBodyReceivedByChunk([promise, callback = WTFMove(actionCallback), globalObject, data = SharedBuffer::create()] (auto&& result) mutable { |
398 | ExecState* exec = globalObject->globalExec(); |
399 | if (result.hasException()) { |
400 | promise->reject(exec, createTypeError(exec, result.exception().message())); |
401 | return; |
402 | } |
403 | |
404 | if (auto chunk = result.returnValue()) |
405 | data->append(reinterpret_cast<const char*>(chunk->data), chunk->size); |
406 | else { |
407 | VM& vm = exec->vm(); |
408 | JSLockHolder lock(vm); |
409 | |
410 | callback(exec, data->data(), data->size()); |
411 | } |
412 | }); |
413 | return; |
414 | } |
415 | |
416 | auto body = inputResponse->consumeBody(); |
417 | WTF::switchOn(body, [&] (Ref<FormData>& formData) { |
418 | if (auto buffer = formData->asSharedBuffer()) { |
419 | VM& vm = exec->vm(); |
420 | JSLockHolder lock(vm); |
421 | |
422 | actionCallback(exec, buffer->data(), buffer->size()); |
423 | return; |
424 | } |
425 | // FIXME: http://webkit.org/b/184886> Implement loading for the Blob type |
426 | promise->reject(exec, createTypeError(exec, "Unexpected Response's Content-type"_s )); |
427 | }, [&] (Ref<SharedBuffer>& buffer) { |
428 | VM& vm = exec->vm(); |
429 | JSLockHolder lock(vm); |
430 | |
431 | actionCallback(exec, buffer->data(), buffer->size()); |
432 | }, [&] (std::nullptr_t&) { |
433 | promise->reject(exec, createTypeError(exec, "Unexpected Response's Content-type"_s )); |
434 | }); |
435 | } |
436 | |
437 | void JSDOMWindowBase::compileStreaming(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSPromiseDeferred* promise, JSC::JSValue source) |
438 | { |
439 | ASSERT(source); |
440 | |
441 | VM& vm = exec->vm(); |
442 | |
443 | ASSERT(vm.promiseDeferredTimer->hasPendingPromise(promise)); |
444 | ASSERT(vm.promiseDeferredTimer->hasDependancyInPendingPromise(promise, globalObject)); |
445 | |
446 | if (auto inputResponse = JSFetchResponse::toWrapped(vm, source)) { |
447 | handleResponseOnStreamingAction(globalObject, exec, inputResponse, promise, [promise] (JSC::ExecState* exec, const char* data, size_t byteSize) mutable { |
448 | if (auto arrayBuffer = tryAllocate(exec, promise, data, byteSize)) |
449 | JSC::WebAssemblyPrototype::webAssemblyModuleValidateAsync(exec, promise, WTFMove(*arrayBuffer)); |
450 | }); |
451 | } else |
452 | promise->reject(exec, createTypeError(exec, "first argument must be an Response or Promise for Response"_s )); |
453 | } |
454 | |
455 | void JSDOMWindowBase::instantiateStreaming(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSPromiseDeferred* promise, JSC::JSValue source, JSC::JSObject* importedObject) |
456 | { |
457 | ASSERT(source); |
458 | |
459 | VM& vm = exec->vm(); |
460 | |
461 | ASSERT(vm.promiseDeferredTimer->hasPendingPromise(promise)); |
462 | ASSERT(vm.promiseDeferredTimer->hasDependancyInPendingPromise(promise, globalObject)); |
463 | ASSERT(vm.promiseDeferredTimer->hasDependancyInPendingPromise(promise, importedObject)); |
464 | |
465 | if (auto inputResponse = JSFetchResponse::toWrapped(vm, source)) { |
466 | handleResponseOnStreamingAction(globalObject, exec, inputResponse, promise, [promise, importedObject] (JSC::ExecState* exec, const char* data, size_t byteSize) mutable { |
467 | if (auto arrayBuffer = tryAllocate(exec, promise, data, byteSize)) |
468 | JSC::WebAssemblyPrototype::webAssemblyModuleInstantinateAsync(exec, promise, WTFMove(*arrayBuffer), importedObject); |
469 | }); |
470 | } else |
471 | promise->reject(exec, createTypeError(exec, "first argument must be an Response or Promise for Response"_s )); |
472 | } |
473 | #endif |
474 | |
475 | } // namespace WebCore |
476 | |