diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/workers/WorkerGlobalScope.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/workers/WorkerGlobalScope.cpp')
-rw-r--r-- | Source/WebCore/workers/WorkerGlobalScope.cpp | 362 |
1 files changed, 198 insertions, 164 deletions
diff --git a/Source/WebCore/workers/WorkerGlobalScope.cpp b/Source/WebCore/workers/WorkerGlobalScope.cpp index 2889236f7..9b357096b 100644 --- a/Source/WebCore/workers/WorkerGlobalScope.cpp +++ b/Source/WebCore/workers/WorkerGlobalScope.cpp @@ -11,107 +11,112 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "config.h" - #include "WorkerGlobalScope.h" -#include "ActiveDOMObject.h" #include "ContentSecurityPolicy.h" -#include "DOMTimer.h" -#include "DOMURL.h" -#include "DOMWindow.h" -#include "ErrorEvent.h" -#include "Event.h" -#include "EventException.h" +#include "Crypto.h" #include "ExceptionCode.h" -#include "InspectorConsoleInstrumentation.h" -#include "URL.h" -#include "MessagePort.h" -#include "NotImplemented.h" +#include "IDBConnectionProxy.h" +#include "InspectorInstrumentation.h" +#include "Performance.h" #include "ScheduledAction.h" -#include "ScriptCallStack.h" #include "ScriptSourceCode.h" #include "SecurityOrigin.h" +#include "SecurityOriginPolicy.h" +#include "SocketProvider.h" #include "WorkerInspectorController.h" +#include "WorkerLoaderProxy.h" #include "WorkerLocation.h" #include "WorkerNavigator.h" -#include "WorkerObjectProxy.h" +#include "WorkerReportingProxy.h" #include "WorkerScriptLoader.h" #include "WorkerThread.h" -#include "WorkerThreadableLoader.h" -#include "XMLHttpRequestException.h" -#include <bindings/ScriptValue.h> -#include <wtf/RefPtr.h> +#include <inspector/ScriptArguments.h> +#include <inspector/ScriptCallStack.h> -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) -#include "NotificationCenter.h" -#endif +using namespace Inspector; namespace WebCore { -class CloseWorkerGlobalScopeTask : public ScriptExecutionContext::Task { -public: - static PassOwnPtr<CloseWorkerGlobalScopeTask> create() - { - return adoptPtr(new CloseWorkerGlobalScopeTask); - } - - virtual void performTask(ScriptExecutionContext *context) - { - ASSERT_WITH_SECURITY_IMPLICATION(context->isWorkerGlobalScope()); - WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(context); - // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop(). - workerGlobalScope->thread()->workerReportingProxy().workerGlobalScopeClosed(); - } - - virtual bool isCleanupTask() const { return true; } -}; - -WorkerGlobalScope::WorkerGlobalScope(const URL& url, const String& userAgent, std::unique_ptr<GroupSettings> settings, WorkerThread* thread, PassRefPtr<SecurityOrigin> topOrigin) +WorkerGlobalScope::WorkerGlobalScope(const URL& url, const String& identifier, const String& userAgent, WorkerThread& thread, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, MonotonicTime timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider) : m_url(url) + , m_identifier(identifier) , m_userAgent(userAgent) - , m_groupSettings(std::move(settings)) - , m_script(adoptPtr(new WorkerScriptController(this))) , m_thread(thread) -#if ENABLE(INSPECTOR) - , m_workerInspectorController(std::make_unique<WorkerInspectorController>(*this)) -#endif - , m_closing(false) + , m_script(std::make_unique<WorkerScriptController>(this)) + , m_inspectorController(std::make_unique<WorkerInspectorController>(*this)) + , m_shouldBypassMainWorldContentSecurityPolicy(shouldBypassMainWorldContentSecurityPolicy) , m_eventQueue(*this) - , m_topOrigin(topOrigin) + , m_topOrigin(WTFMove(topOrigin)) +#if ENABLE(INDEXED_DATABASE) + , m_connectionProxy(connectionProxy) +#endif +#if ENABLE(WEB_SOCKETS) + , m_socketProvider(socketProvider) +#endif +#if ENABLE(WEB_TIMING) + , m_performance(Performance::create(*this, timeOrigin)) +#endif { - setSecurityOrigin(SecurityOrigin::create(url)); +#if !ENABLE(INDEXED_DATABASE) + UNUSED_PARAM(connectionProxy); +#endif +#if !ENABLE(WEB_SOCKETS) + UNUSED_PARAM(socketProvider); +#endif +#if !ENABLE(WEB_TIMING) + UNUSED_PARAM(timeOrigin); +#endif + + auto origin = SecurityOrigin::create(url); + if (m_topOrigin->hasUniversalAccess()) + origin->grantUniversalAccess(); + if (m_topOrigin->needsStorageAccessFromFileURLsQuirk()) + origin->grantStorageAccessFromFileURLsQuirk(); + + setSecurityOriginPolicy(SecurityOriginPolicy::create(WTFMove(origin))); + setContentSecurityPolicy(std::make_unique<ContentSecurityPolicy>(*this)); } WorkerGlobalScope::~WorkerGlobalScope() { - ASSERT(currentThread() == thread()->threadID()); + ASSERT(currentThread() == thread().threadID()); - // Make sure we have no observers. - notifyObserversOfStop(); +#if ENABLE(WEB_TIMING) + m_performance = nullptr; +#endif // Notify proxy that we are going away. This can free the WorkerThread object, so do not access it after this. - thread()->workerReportingProxy().workerGlobalScopeDestroyed(); + thread().workerReportingProxy().workerGlobalScopeDestroyed(); } -void WorkerGlobalScope::applyContentSecurityPolicyFromString(const String& policy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType) +void WorkerGlobalScope::removeAllEventListeners() { - setContentSecurityPolicy(ContentSecurityPolicy::create(this)); - contentSecurityPolicy()->didReceiveHeader(policy, contentSecurityPolicyType); + EventTarget::removeAllEventListeners(); + +#if ENABLE(WEB_TIMING) + m_performance->removeAllEventListeners(); +#endif +} + +void WorkerGlobalScope::applyContentSecurityPolicyResponseHeaders(const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders) +{ + contentSecurityPolicy()->didReceiveHeaders(contentSecurityPolicyResponseHeaders); } URL WorkerGlobalScope::completeURL(const String& url) const @@ -134,11 +139,41 @@ void WorkerGlobalScope::disableEval(const String& errorMessage) m_script->disableEval(errorMessage); } -WorkerLocation* WorkerGlobalScope::location() const +#if ENABLE(WEB_SOCKETS) + +SocketProvider* WorkerGlobalScope::socketProvider() +{ + return m_socketProvider.get(); +} + +#endif + +#if ENABLE(INDEXED_DATABASE) + +IDBClient::IDBConnectionProxy* WorkerGlobalScope::idbConnectionProxy() +{ +#if ENABLE(INDEXED_DATABASE_IN_WORKERS) + return m_connectionProxy.get(); +#else + return nullptr; +#endif +} + +void WorkerGlobalScope::stopIndexedDatabase() +{ +#if ENABLE(INDEXED_DATABASE_IN_WORKERS) + ASSERT(m_connectionProxy); + m_connectionProxy->forgetActivityForCurrentThread(); +#endif +} + +#endif // ENABLE(INDEXED_DATABASE) + +WorkerLocation& WorkerGlobalScope::location() const { if (!m_location) m_location = WorkerLocation::create(m_url); - return m_location.get(); + return *m_location; } void WorkerGlobalScope::close() @@ -150,93 +185,83 @@ void WorkerGlobalScope::close() // After m_closing is set, all the tasks in the queue continue to be fetched but only // tasks with isCleanupTask()==true will be executed. m_closing = true; - postTask(CloseWorkerGlobalScopeTask::create()); + postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) { + ASSERT_WITH_SECURITY_IMPLICATION(is<WorkerGlobalScope>(context)); + WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context); + // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop(). + workerGlobalScope.thread().workerReportingProxy().workerGlobalScopeClosed(); + } }); } -WorkerNavigator* WorkerGlobalScope::navigator() const +WorkerNavigator& WorkerGlobalScope::navigator() const { if (!m_navigator) m_navigator = WorkerNavigator::create(m_userAgent); - return m_navigator.get(); -} - -bool WorkerGlobalScope::hasPendingActivity() const -{ - ActiveDOMObjectsSet::const_iterator activeObjectsEnd = activeDOMObjects().end(); - for (ActiveDOMObjectsSet::const_iterator iter = activeDOMObjects().begin(); iter != activeObjectsEnd; ++iter) { - if ((*iter)->hasPendingActivity()) - return true; - } - - HashSet<MessagePort*>::const_iterator messagePortsEnd = messagePorts().end(); - for (HashSet<MessagePort*>::const_iterator iter = messagePorts().begin(); iter != messagePortsEnd; ++iter) { - if ((*iter)->hasPendingActivity()) - return true; - } - - return false; + return *m_navigator; } -void WorkerGlobalScope::postTask(PassOwnPtr<Task> task) +void WorkerGlobalScope::postTask(Task&& task) { - thread()->runLoop().postTask(task); + thread().runLoop().postTask(WTFMove(task)); } -int WorkerGlobalScope::setTimeout(PassOwnPtr<ScheduledAction> action, int timeout) +int WorkerGlobalScope::setTimeout(std::unique_ptr<ScheduledAction> action, int timeout) { - return DOMTimer::install(scriptExecutionContext(), action, timeout, true); + return DOMTimer::install(*this, WTFMove(action), std::chrono::milliseconds(timeout), true); } void WorkerGlobalScope::clearTimeout(int timeoutId) { - DOMTimer::removeById(scriptExecutionContext(), timeoutId); + DOMTimer::removeById(*this, timeoutId); } -int WorkerGlobalScope::setInterval(PassOwnPtr<ScheduledAction> action, int timeout) +int WorkerGlobalScope::setInterval(std::unique_ptr<ScheduledAction> action, int timeout) { - return DOMTimer::install(scriptExecutionContext(), action, timeout, false); + return DOMTimer::install(*this, WTFMove(action), std::chrono::milliseconds(timeout), false); } void WorkerGlobalScope::clearInterval(int timeoutId) { - DOMTimer::removeById(scriptExecutionContext(), timeoutId); + DOMTimer::removeById(*this, timeoutId); } -void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionCode& ec) +ExceptionOr<void> WorkerGlobalScope::importScripts(const Vector<String>& urls) { ASSERT(contentSecurityPolicy()); - ec = 0; - Vector<String>::const_iterator urlsEnd = urls.end(); + Vector<URL> completedURLs; - for (Vector<String>::const_iterator it = urls.begin(); it != urlsEnd; ++it) { - const URL& url = scriptExecutionContext()->completeURL(*it); - if (!url.isValid()) { - ec = SYNTAX_ERR; - return; - } - completedURLs.append(url); + completedURLs.reserveInitialCapacity(urls.size()); + for (auto& entry : urls) { + URL url = completeURL(entry); + if (!url.isValid()) + return Exception { SYNTAX_ERR }; + completedURLs.uncheckedAppend(WTFMove(url)); } - Vector<URL>::const_iterator end = completedURLs.end(); - for (Vector<URL>::const_iterator it = completedURLs.begin(); it != end; ++it) { - RefPtr<WorkerScriptLoader> scriptLoader(WorkerScriptLoader::create()); - scriptLoader->loadSynchronously(scriptExecutionContext(), *it, AllowCrossOriginRequests); + for (auto& url : completedURLs) { + // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved. + bool shouldBypassMainWorldContentSecurityPolicy = this->shouldBypassMainWorldContentSecurityPolicy(); + if (!shouldBypassMainWorldContentSecurityPolicy && !contentSecurityPolicy()->allowScriptFromSource(url)) + return Exception { NETWORK_ERR }; + + auto scriptLoader = WorkerScriptLoader::create(); + scriptLoader->loadSynchronously(this, url, FetchOptions::Mode::NoCors, shouldBypassMainWorldContentSecurityPolicy ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceScriptSrcDirective, resourceRequestIdentifier()); // If the fetching attempt failed, throw a NETWORK_ERR exception and abort all these steps. - if (scriptLoader->failed()) { - ec = XMLHttpRequestException::NETWORK_ERR; - return; - } + if (scriptLoader->failed()) + return Exception { NETWORK_ERR }; - InspectorInstrumentation::scriptImported(scriptExecutionContext(), scriptLoader->identifier(), scriptLoader->script()); + InspectorInstrumentation::scriptImported(*this, scriptLoader->identifier(), scriptLoader->script()); - Deprecated::ScriptValue exception; - m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &exception); - if (!exception.hasNoValue()) { + NakedPtr<JSC::Exception> exception; + m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), exception); + if (exception) { m_script->setException(exception); - return; + return { }; } } + + return { }; } EventTarget* WorkerGlobalScope::errorEventTarget() @@ -244,45 +269,44 @@ EventTarget* WorkerGlobalScope::errorEventTarget() return this; } -void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>) +void WorkerGlobalScope::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr<ScriptCallStack>&&) { - thread()->workerReportingProxy().postExceptionToWorkerObject(errorMessage, lineNumber, columnNumber, sourceURL); + thread().workerReportingProxy().postExceptionToWorkerObject(errorMessage, lineNumber, columnNumber, sourceURL); } -void WorkerGlobalScope::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier) +void WorkerGlobalScope::addConsoleMessage(std::unique_ptr<Inspector::ConsoleMessage>&& message) { if (!isContextThread()) { - postTask(AddConsoleMessageTask::create(source, level, message)); + postTask(AddConsoleMessageTask(message->source(), message->level(), message->message())); return; } - thread()->workerReportingProxy().postConsoleMessageToWorkerObject(source, level, message, 0, 0, String()); - addMessageToWorkerConsole(source, level, message, String(), 0, 0, 0, 0, requestIdentifier); + InspectorInstrumentation::addMessageToConsole(*this, WTFMove(message)); } -void WorkerGlobalScope::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, PassRefPtr<ScriptCallStack> callStack, JSC::ExecState* state, unsigned long requestIdentifier) +void WorkerGlobalScope::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier) +{ + addMessage(source, level, message, { }, 0, 0, nullptr, nullptr, requestIdentifier); +} + +void WorkerGlobalScope::addMessage(MessageSource source, MessageLevel level, const String& messageText, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, RefPtr<ScriptCallStack>&& callStack, JSC::ExecState* state, unsigned long requestIdentifier) { if (!isContextThread()) { - postTask(AddConsoleMessageTask::create(source, level, message)); + postTask(AddConsoleMessageTask(source, level, messageText)); return; } - thread()->workerReportingProxy().postConsoleMessageToWorkerObject(source, level, message, lineNumber, columnNumber, sourceURL); - addMessageToWorkerConsole(source, level, message, sourceURL, lineNumber, columnNumber, callStack, state, requestIdentifier); -} - -void WorkerGlobalScope::addMessageToWorkerConsole(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, PassRefPtr<ScriptCallStack> callStack, JSC::ExecState* state, unsigned long requestIdentifier) -{ - ASSERT(isContextThread()); + std::unique_ptr<Inspector::ConsoleMessage> message; if (callStack) - InspectorInstrumentation::addMessageToConsole(this, source, LogMessageType, level, message, callStack, requestIdentifier); + message = std::make_unique<Inspector::ConsoleMessage>(source, MessageType::Log, level, messageText, callStack.releaseNonNull(), requestIdentifier); else - InspectorInstrumentation::addMessageToConsole(this, source, LogMessageType, level, message, sourceURL, lineNumber, columnNumber, state, requestIdentifier); + message = std::make_unique<Inspector::ConsoleMessage>(source, MessageType::Log, level, messageText, sourceURL, lineNumber, columnNumber, state, requestIdentifier); + InspectorInstrumentation::addMessageToConsole(*this, WTFMove(message)); } bool WorkerGlobalScope::isContextThread() const { - return currentThread() == thread()->threadID(); + return currentThread() == thread().threadID(); } bool WorkerGlobalScope::isJSExecutionForbidden() const @@ -290,56 +314,66 @@ bool WorkerGlobalScope::isJSExecutionForbidden() const return m_script->isExecutionForbidden(); } -WorkerGlobalScope::Observer::Observer(WorkerGlobalScope* context) - : m_context(context) +WorkerEventQueue& WorkerGlobalScope::eventQueue() const { - ASSERT(m_context && m_context->isContextThread()); - m_context->registerObserver(this); + return m_eventQueue; } -WorkerGlobalScope::Observer::~Observer() -{ - if (!m_context) - return; - ASSERT(m_context->isContextThread()); - m_context->unregisterObserver(this); -} +#if ENABLE(SUBTLE_CRYPTO) -void WorkerGlobalScope::Observer::stopObserving() +bool WorkerGlobalScope::wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) { - if (!m_context) - return; - ASSERT(m_context->isContextThread()); - m_context->unregisterObserver(this); - m_context = 0; + bool result = false; + bool done = false; + m_thread.workerLoaderProxy().postTaskToLoader([&result, &key, &wrappedKey, &done, workerGlobalScope = this](ScriptExecutionContext& context) { + result = context.wrapCryptoKey(key, wrappedKey); + done = true; + workerGlobalScope->postTask([](ScriptExecutionContext& context) { + ASSERT_UNUSED(context, context.isWorkerGlobalScope()); + }); + }); + + auto waitResult = MessageQueueMessageReceived; + while (!done && waitResult != MessageQueueTerminated) + waitResult = m_thread.runLoop().runInMode(this, WorkerRunLoop::defaultMode()); + + return result; } -void WorkerGlobalScope::registerObserver(Observer* observer) +bool WorkerGlobalScope::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) { - ASSERT(observer); - m_workerObservers.add(observer); + bool result = false, done = false; + m_thread.workerLoaderProxy().postTaskToLoader([&result, &wrappedKey, &key, &done, workerGlobalScope = this](ScriptExecutionContext& context) { + result = context.unwrapCryptoKey(wrappedKey, key); + done = true; + workerGlobalScope->postTask([](ScriptExecutionContext& context) { + ASSERT_UNUSED(context, context.isWorkerGlobalScope()); + }); + }); + + auto waitResult = MessageQueueMessageReceived; + while (!done && waitResult != MessageQueueTerminated) + waitResult = m_thread.runLoop().runInMode(this, WorkerRunLoop::defaultMode()); + + return result; } -void WorkerGlobalScope::unregisterObserver(Observer* observer) -{ - ASSERT(observer); - m_workerObservers.remove(observer); -} +#endif // ENABLE(SUBTLE_CRYPTO) -void WorkerGlobalScope::notifyObserversOfStop() +Crypto& WorkerGlobalScope::crypto() { - HashSet<Observer*>::iterator iter = m_workerObservers.begin(); - while (iter != m_workerObservers.end()) { - WorkerGlobalScope::Observer* observer = *iter; - observer->stopObserving(); - observer->notifyStop(); - iter = m_workerObservers.begin(); - } + if (!m_crypto) + m_crypto = Crypto::create(*this); + return *m_crypto; } -WorkerEventQueue& WorkerGlobalScope::eventQueue() const +#if ENABLE(WEB_TIMING) + +Performance& WorkerGlobalScope::performance() const { - return m_eventQueue; + return *m_performance; } +#endif + } // namespace WebCore |