| Index: third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
|
| diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
|
| index d3fb81674a20f1c1b318e39c310153048daa1291..6000131f69dae4b9b27da3483f5b12cff1948179 100644
|
| --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
|
| +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
|
| @@ -28,25 +28,18 @@
|
| #include "core/workers/WorkerGlobalScope.h"
|
|
|
| #include "bindings/core/v8/ExceptionState.h"
|
| -#include "bindings/core/v8/ScheduledAction.h"
|
| #include "bindings/core/v8/ScriptSourceCode.h"
|
| -#include "bindings/core/v8/ScriptValue.h"
|
| #include "bindings/core/v8/SourceLocation.h"
|
| #include "bindings/core/v8/V8AbstractEventListener.h"
|
| -#include "bindings/core/v8/V8CacheOptions.h"
|
| #include "core/dom/ActiveDOMObject.h"
|
| #include "core/dom/ContextLifecycleNotifier.h"
|
| #include "core/dom/CrossThreadTask.h"
|
| -#include "core/dom/DOMURL.h"
|
| #include "core/dom/ExceptionCode.h"
|
| -#include "core/dom/MessagePort.h"
|
| #include "core/events/ErrorEvent.h"
|
| #include "core/events/Event.h"
|
| #include "core/fetch/MemoryCache.h"
|
| -#include "core/frame/DOMTimer.h"
|
| #include "core/frame/DOMTimerCoordinator.h"
|
| #include "core/frame/Deprecation.h"
|
| -#include "core/frame/LocalDOMWindow.h"
|
| #include "core/inspector/ConsoleMessage.h"
|
| #include "core/inspector/InspectorInstrumentation.h"
|
| #include "core/inspector/WorkerInspectorController.h"
|
| @@ -65,61 +58,46 @@
|
| #include "public/platform/Platform.h"
|
| #include "public/platform/WebScheduler.h"
|
| #include "public/platform/WebURLRequest.h"
|
| -#include <memory>
|
| +#include "wtf/Assertions.h"
|
| +#include "wtf/RefPtr.h"
|
|
|
| namespace blink {
|
|
|
| -WorkerGlobalScope::WorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, double timeOrigin, std::unique_ptr<SecurityOrigin::PrivilegeData> starterOriginPrivilageData, WorkerClients* workerClients)
|
| - : m_url(url)
|
| - , m_userAgent(userAgent)
|
| - , m_v8CacheOptions(V8CacheOptionsDefault)
|
| - , m_scriptController(WorkerOrWorkletScriptController::create(this, thread->isolate()))
|
| - , m_thread(thread)
|
| - , m_workerInspectorController(WorkerInspectorController::create(this))
|
| - , m_closing(false)
|
| - , m_eventQueue(WorkerEventQueue::create(this))
|
| - , m_workerClients(workerClients)
|
| - , m_timers(Platform::current()->currentThread()->scheduler()->timerTaskRunner()->adoptClone())
|
| - , m_timeOrigin(timeOrigin)
|
| -{
|
| - setSecurityOrigin(SecurityOrigin::create(url));
|
| - if (starterOriginPrivilageData)
|
| - getSecurityOrigin()->transferPrivilegesFrom(std::move(starterOriginPrivilageData));
|
| +namespace {
|
|
|
| - if (m_workerClients)
|
| - m_workerClients->reattachThread();
|
| +void removeURLFromMemoryCacheInternal(const KURL& url)
|
| +{
|
| + memoryCache()->removeURLFromCache(url);
|
| }
|
|
|
| +} // namespace
|
| +
|
| WorkerGlobalScope::~WorkerGlobalScope()
|
| {
|
| DCHECK(!m_scriptController);
|
| DCHECK(!m_workerInspectorController);
|
| }
|
|
|
| -void WorkerGlobalScope::applyContentSecurityPolicyFromVector(const Vector<CSPHeaderAndType>& headers)
|
| -{
|
| - if (!contentSecurityPolicy()) {
|
| - ContentSecurityPolicy* csp = ContentSecurityPolicy::create();
|
| - setContentSecurityPolicy(csp);
|
| - }
|
| - for (const auto& policyAndType : headers)
|
| - contentSecurityPolicy()->didReceiveHeader(policyAndType.first, policyAndType.second, ContentSecurityPolicyHeaderSourceHTTP);
|
| - contentSecurityPolicy()->bindToExecutionContext(getExecutionContext());
|
| -}
|
| -
|
| -ExecutionContext* WorkerGlobalScope::getExecutionContext() const
|
| +void WorkerGlobalScope::countFeature(UseCounter::Feature) const
|
| {
|
| - return const_cast<WorkerGlobalScope*>(this);
|
| + // TODO(nhiroki): How should we count features for shared/service workers?
|
| + // (http://crbug.com/376039)
|
| }
|
|
|
| -const KURL& WorkerGlobalScope::virtualURL() const
|
| +void WorkerGlobalScope::countDeprecation(UseCounter::Feature feature) const
|
| {
|
| - return m_url;
|
| -}
|
| + // TODO(nhiroki): How should we count features for shared/service workers?
|
| + // (http://crbug.com/376039)
|
|
|
| -KURL WorkerGlobalScope::virtualCompleteURL(const String& url) const
|
| -{
|
| - return completeURL(url);
|
| + DCHECK(isSharedWorkerGlobalScope() || isServiceWorkerGlobalScope() || isCompositorWorkerGlobalScope());
|
| + // For each deprecated feature, send console message at most once
|
| + // per worker lifecycle.
|
| + if (!m_deprecationWarningBits.hasRecordedMeasurement(feature)) {
|
| + m_deprecationWarningBits.recordMeasurement(feature);
|
| + DCHECK(!Deprecation::deprecationMessage(feature).isEmpty());
|
| + DCHECK(getExecutionContext());
|
| + getExecutionContext()->addConsoleMessage(ConsoleMessage::create(DeprecationMessageSource, WarningMessageLevel, Deprecation::deprecationMessage(feature)));
|
| + }
|
| }
|
|
|
| KURL WorkerGlobalScope::completeURL(const String& url) const
|
| @@ -132,19 +110,47 @@ KURL WorkerGlobalScope::completeURL(const String& url) const
|
| return KURL(m_url, url);
|
| }
|
|
|
| -String WorkerGlobalScope::userAgent() const
|
| +void WorkerGlobalScope::dispose()
|
| {
|
| - return m_userAgent;
|
| + DCHECK(thread()->isCurrentThread());
|
| + stopActiveDOMObjects();
|
| +
|
| + // Event listeners would keep DOMWrapperWorld objects alive for too long.
|
| + // Also, they have references to JS objects, which become dangling once Heap
|
| + // is destroyed.
|
| + for (auto it = m_eventListeners.begin(); it != m_eventListeners.end(); ) {
|
| + V8AbstractEventListener* listener = *it;
|
| + // clearListenerObject() will unregister the listener from
|
| + // m_eventListeners, and invalidate the iterator, so we have to advance
|
| + // it first.
|
| + ++it;
|
| + listener->clearListenerObject();
|
| + }
|
| + removeAllEventListeners();
|
| +
|
| + clearScript();
|
| + clearInspector();
|
| + m_eventQueue->close();
|
| + m_thread = nullptr;
|
| }
|
|
|
| -void WorkerGlobalScope::disableEval(const String& errorMessage)
|
| +void WorkerGlobalScope::exceptionUnhandled(const String& errorMessage, std::unique_ptr<SourceLocation> location)
|
| {
|
| - m_scriptController->disableEval(errorMessage);
|
| + if (WorkerThreadDebugger* debugger = WorkerThreadDebugger::from(thread()->isolate()))
|
| + debugger->exceptionThrown(errorMessage, std::move(location));
|
| }
|
|
|
| -DOMTimerCoordinator* WorkerGlobalScope::timers()
|
| +void WorkerGlobalScope::registerEventListener(V8AbstractEventListener* eventListener)
|
| {
|
| - return &m_timers;
|
| + bool newEntry = m_eventListeners.add(eventListener).isNewEntry;
|
| + RELEASE_ASSERT(newEntry);
|
| +}
|
| +
|
| +void WorkerGlobalScope::deregisterEventListener(V8AbstractEventListener* eventListener)
|
| +{
|
| + auto it = m_eventListeners.find(eventListener);
|
| + RELEASE_ASSERT(it != m_eventListeners.end());
|
| + m_eventListeners.remove(it);
|
| }
|
|
|
| WorkerLocation* WorkerGlobalScope::location() const
|
| @@ -154,13 +160,6 @@ WorkerLocation* WorkerGlobalScope::location() const
|
| return m_location.get();
|
| }
|
|
|
| -void WorkerGlobalScope::close()
|
| -{
|
| - // Let current script run to completion, but tell the worker micro task
|
| - // runner to tear down the thread after this task.
|
| - m_closing = true;
|
| -}
|
| -
|
| WorkerNavigator* WorkerGlobalScope::navigator() const
|
| {
|
| if (!m_navigator)
|
| @@ -168,51 +167,11 @@ WorkerNavigator* WorkerGlobalScope::navigator() const
|
| return m_navigator.get();
|
| }
|
|
|
| -void WorkerGlobalScope::postTask(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task, const String& taskNameForInstrumentation)
|
| -{
|
| - thread()->postTask(location, std::move(task), !taskNameForInstrumentation.isEmpty());
|
| -}
|
| -
|
| -void WorkerGlobalScope::clearScript()
|
| -{
|
| - DCHECK(m_scriptController);
|
| - m_scriptController->dispose();
|
| - m_scriptController.clear();
|
| -}
|
| -
|
| -void WorkerGlobalScope::clearInspector()
|
| -{
|
| - if (m_workerInspectorController) {
|
| - m_workerInspectorController->dispose();
|
| - m_workerInspectorController.clear();
|
| - }
|
| -}
|
| -
|
| -void WorkerGlobalScope::dispose()
|
| -{
|
| - DCHECK(thread()->isCurrentThread());
|
| - stopActiveDOMObjects();
|
| -
|
| - // Event listeners would keep DOMWrapperWorld objects alive for too long. Also, they have references to JS objects,
|
| - // which become dangling once Heap is destroyed.
|
| - for (auto it = m_eventListeners.begin(); it != m_eventListeners.end(); ) {
|
| - V8AbstractEventListener* listener = *it;
|
| - // clearListenerObject() will unregister the listener from
|
| - // m_eventListeners, and invalidate the iterator, so we have to advance
|
| - // it first.
|
| - ++it;
|
| - listener->clearListenerObject();
|
| - }
|
| - removeAllEventListeners();
|
| -
|
| - clearScript();
|
| - clearInspector();
|
| - m_eventQueue->close();
|
| - m_thread = nullptr;
|
| -}
|
| -
|
| -void WorkerGlobalScope::didEvaluateWorkerScript()
|
| +void WorkerGlobalScope::close()
|
| {
|
| + // Let current script run to completion, but tell the worker micro task
|
| + // runner to tear down the thread after this task.
|
| + m_closing = true;
|
| }
|
|
|
| void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState& exceptionState)
|
| @@ -241,7 +200,8 @@ void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState
|
| scriptLoader->setRequestContext(WebURLRequest::RequestContextScript);
|
| scriptLoader->loadSynchronously(executionContext, completeURL, AllowCrossOriginRequests, executionContext.securityContext().addressSpace());
|
|
|
| - // If the fetching attempt failed, throw a NetworkError exception and abort all these steps.
|
| + // If the fetching attempt failed, throw a NetworkError exception and
|
| + // abort all these steps.
|
| if (scriptLoader->failed()) {
|
| exceptionState.throwDOMException(NetworkError, "The script at '" + completeURL.elidedString() + "' failed to load.");
|
| return;
|
| @@ -261,38 +221,45 @@ void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState
|
| }
|
| }
|
|
|
| -EventTarget* WorkerGlobalScope::errorEventTarget()
|
| +v8::Local<v8::Object> WorkerGlobalScope::wrap(v8::Isolate*, v8::Local<v8::Object> creationContext)
|
| {
|
| - return this;
|
| + // WorkerGlobalScope must never be wrapped with wrap method. The global
|
| + // object of ECMAScript environment is used as the wrapper.
|
| + RELEASE_NOTREACHED();
|
| + return v8::Local<v8::Object>();
|
| }
|
|
|
| -void WorkerGlobalScope::exceptionThrown(const String& errorMessage, std::unique_ptr<SourceLocation> location)
|
| +v8::Local<v8::Object> WorkerGlobalScope::associateWithWrapper(v8::Isolate*, const WrapperTypeInfo*, v8::Local<v8::Object> wrapper)
|
| {
|
| - thread()->workerReportingProxy().reportException(errorMessage, std::move(location));
|
| + RELEASE_NOTREACHED(); // same as wrap method
|
| + return v8::Local<v8::Object>();
|
| }
|
|
|
| -void WorkerGlobalScope::addConsoleMessage(ConsoleMessage* consoleMessage)
|
| +bool WorkerGlobalScope::isJSExecutionForbidden() const
|
| {
|
| - DCHECK(isContextThread());
|
| - thread()->workerReportingProxy().reportConsoleMessage(consoleMessage);
|
| - addMessageToWorkerConsole(consoleMessage);
|
| + return m_scriptController->isExecutionForbidden();
|
| }
|
|
|
| -void WorkerGlobalScope::addMessageToWorkerConsole(ConsoleMessage* consoleMessage)
|
| +bool WorkerGlobalScope::isContextThread() const
|
| {
|
| - DCHECK(isContextThread());
|
| - if (WorkerThreadDebugger* debugger = WorkerThreadDebugger::from(thread()->isolate()))
|
| - debugger->addConsoleMessage(consoleMessage);
|
| + return thread()->isCurrentThread();
|
| }
|
|
|
| -bool WorkerGlobalScope::isContextThread() const
|
| +void WorkerGlobalScope::disableEval(const String& errorMessage)
|
| {
|
| - return thread()->isCurrentThread();
|
| + m_scriptController->disableEval(errorMessage);
|
| }
|
|
|
| -bool WorkerGlobalScope::isJSExecutionForbidden() const
|
| +void WorkerGlobalScope::postTask(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task, const String& taskNameForInstrumentation)
|
| {
|
| - return m_scriptController->isExecutionForbidden();
|
| + thread()->postTask(location, std::move(task), !taskNameForInstrumentation.isEmpty());
|
| +}
|
| +
|
| +void WorkerGlobalScope::addConsoleMessage(ConsoleMessage* consoleMessage)
|
| +{
|
| + DCHECK(isContextThread());
|
| + thread()->workerReportingProxy().reportConsoleMessage(consoleMessage);
|
| + addMessageToWorkerConsole(consoleMessage);
|
| }
|
|
|
| WorkerEventQueue* WorkerGlobalScope::getEventQueue() const
|
| @@ -300,83 +267,92 @@ WorkerEventQueue* WorkerGlobalScope::getEventQueue() const
|
| return m_eventQueue.get();
|
| }
|
|
|
| -void WorkerGlobalScope::registerEventListener(V8AbstractEventListener* eventListener)
|
| +bool WorkerGlobalScope::isSecureContext(String& errorMessage, const SecureContextCheck privilegeContextCheck) const
|
| {
|
| - bool newEntry = m_eventListeners.add(eventListener).isNewEntry;
|
| - RELEASE_ASSERT(newEntry);
|
| + // Until there are APIs that are available in workers and that
|
| + // require a privileged context test that checks ancestors, just do
|
| + // a simple check here. Once we have a need for a real
|
| + // |isSecureContext| check here, we can check the responsible
|
| + // document for a privileged context at worker creation time, pass
|
| + // it in via WorkerThreadStartupData, and check it here.
|
| + if (getSecurityOrigin()->isPotentiallyTrustworthy())
|
| + return true;
|
| + errorMessage = getSecurityOrigin()->isPotentiallyTrustworthyErrorMessage();
|
| + return false;
|
| }
|
|
|
| -void WorkerGlobalScope::deregisterEventListener(V8AbstractEventListener* eventListener)
|
| +ExecutionContext* WorkerGlobalScope::getExecutionContext() const
|
| {
|
| - auto it = m_eventListeners.find(eventListener);
|
| - RELEASE_ASSERT(it != m_eventListeners.end());
|
| - m_eventListeners.remove(it);
|
| + return const_cast<WorkerGlobalScope*>(this);
|
| }
|
|
|
| -void WorkerGlobalScope::countFeature(UseCounter::Feature) const
|
| +WorkerGlobalScope::WorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, double timeOrigin, std::unique_ptr<SecurityOrigin::PrivilegeData> starterOriginPrivilageData, WorkerClients* workerClients)
|
| + : m_url(url)
|
| + , m_userAgent(userAgent)
|
| + , m_v8CacheOptions(V8CacheOptionsDefault)
|
| + , m_scriptController(WorkerOrWorkletScriptController::create(this, thread->isolate()))
|
| + , m_thread(thread)
|
| + , m_workerInspectorController(WorkerInspectorController::create(this))
|
| + , m_closing(false)
|
| + , m_eventQueue(WorkerEventQueue::create(this))
|
| + , m_workerClients(workerClients)
|
| + , m_timers(Platform::current()->currentThread()->scheduler()->timerTaskRunner()->adoptClone())
|
| + , m_timeOrigin(timeOrigin)
|
| {
|
| - // TODO(nhiroki): How should we count features for shared/service workers?
|
| - // (http://crbug.com/376039)
|
| + setSecurityOrigin(SecurityOrigin::create(url));
|
| + if (starterOriginPrivilageData)
|
| + getSecurityOrigin()->transferPrivilegesFrom(std::move(starterOriginPrivilageData));
|
| +
|
| + if (m_workerClients)
|
| + m_workerClients->reattachThread();
|
| }
|
|
|
| -void WorkerGlobalScope::countDeprecation(UseCounter::Feature feature) const
|
| +void WorkerGlobalScope::applyContentSecurityPolicyFromVector(const Vector<CSPHeaderAndType>& headers)
|
| {
|
| - // TODO(nhiroki): How should we count features for shared/service workers?
|
| - // (http://crbug.com/376039)
|
| -
|
| - DCHECK(isSharedWorkerGlobalScope() || isServiceWorkerGlobalScope() || isCompositorWorkerGlobalScope());
|
| - // For each deprecated feature, send console message at most once
|
| - // per worker lifecycle.
|
| - if (!m_deprecationWarningBits.hasRecordedMeasurement(feature)) {
|
| - m_deprecationWarningBits.recordMeasurement(feature);
|
| - DCHECK(!Deprecation::deprecationMessage(feature).isEmpty());
|
| - DCHECK(getExecutionContext());
|
| - getExecutionContext()->addConsoleMessage(ConsoleMessage::create(DeprecationMessageSource, WarningMessageLevel, Deprecation::deprecationMessage(feature)));
|
| + if (!contentSecurityPolicy()) {
|
| + ContentSecurityPolicy* csp = ContentSecurityPolicy::create();
|
| + setContentSecurityPolicy(csp);
|
| }
|
| + for (const auto& policyAndType : headers)
|
| + contentSecurityPolicy()->didReceiveHeader(policyAndType.first, policyAndType.second, ContentSecurityPolicyHeaderSourceHTTP);
|
| + contentSecurityPolicy()->bindToExecutionContext(getExecutionContext());
|
| }
|
|
|
| -void WorkerGlobalScope::exceptionUnhandled(const String& errorMessage, std::unique_ptr<SourceLocation> location)
|
| +void WorkerGlobalScope::addMessageToWorkerConsole(ConsoleMessage* consoleMessage)
|
| {
|
| + DCHECK(isContextThread());
|
| if (WorkerThreadDebugger* debugger = WorkerThreadDebugger::from(thread()->isolate()))
|
| - debugger->exceptionThrown(errorMessage, std::move(location));
|
| + debugger->addConsoleMessage(consoleMessage);
|
| }
|
|
|
| -bool WorkerGlobalScope::isSecureContext(String& errorMessage, const SecureContextCheck privilegeContextCheck) const
|
| +void WorkerGlobalScope::exceptionThrown(const String& errorMessage, std::unique_ptr<SourceLocation> location)
|
| {
|
| - // Until there are APIs that are available in workers and that
|
| - // require a privileged context test that checks ancestors, just do
|
| - // a simple check here. Once we have a need for a real
|
| - // |isSecureContext| check here, we can check the responsible
|
| - // document for a privileged context at worker creation time, pass
|
| - // it in via WorkerThreadStartupData, and check it here.
|
| - if (getSecurityOrigin()->isPotentiallyTrustworthy())
|
| - return true;
|
| - errorMessage = getSecurityOrigin()->isPotentiallyTrustworthyErrorMessage();
|
| - return false;
|
| + thread()->workerReportingProxy().reportException(errorMessage, std::move(location));
|
| }
|
|
|
| void WorkerGlobalScope::removeURLFromMemoryCache(const KURL& url)
|
| {
|
| - m_thread->workerLoaderProxy()->postTaskToLoader(createCrossThreadTask(&WorkerGlobalScope::removeURLFromMemoryCacheInternal, url));
|
| + m_thread->workerLoaderProxy()->postTaskToLoader(createCrossThreadTask(&removeURLFromMemoryCacheInternal, url));
|
| }
|
|
|
| -void WorkerGlobalScope::removeURLFromMemoryCacheInternal(const KURL& url)
|
| +KURL WorkerGlobalScope::virtualCompleteURL(const String& url) const
|
| {
|
| - memoryCache()->removeURLFromCache(url);
|
| + return completeURL(url);
|
| }
|
|
|
| -v8::Local<v8::Object> WorkerGlobalScope::wrap(v8::Isolate*, v8::Local<v8::Object> creationContext)
|
| +void WorkerGlobalScope::clearScript()
|
| {
|
| - // WorkerGlobalScope must never be wrapped with wrap method. The global
|
| - // object of ECMAScript environment is used as the wrapper.
|
| - RELEASE_NOTREACHED();
|
| - return v8::Local<v8::Object>();
|
| + DCHECK(m_scriptController);
|
| + m_scriptController->dispose();
|
| + m_scriptController.clear();
|
| }
|
|
|
| -v8::Local<v8::Object> WorkerGlobalScope::associateWithWrapper(v8::Isolate*, const WrapperTypeInfo*, v8::Local<v8::Object> wrapper)
|
| +void WorkerGlobalScope::clearInspector()
|
| {
|
| - RELEASE_NOTREACHED(); // same as wrap method
|
| - return v8::Local<v8::Object>();
|
| + if (m_workerInspectorController) {
|
| + m_workerInspectorController->dispose();
|
| + m_workerInspectorController.clear();
|
| + }
|
| }
|
|
|
| DEFINE_TRACE(WorkerGlobalScope)
|
|
|