| Index: Source/WebCore/workers/DefaultSharedWorkerRepository.cpp
|
| diff --git a/Source/WebCore/workers/DefaultSharedWorkerRepository.cpp b/Source/WebCore/workers/DefaultSharedWorkerRepository.cpp
|
| deleted file mode 100644
|
| index df6f25de7bdb458782855fadc5968848ff0f4ed7..0000000000000000000000000000000000000000
|
| --- a/Source/WebCore/workers/DefaultSharedWorkerRepository.cpp
|
| +++ /dev/null
|
| @@ -1,441 +0,0 @@
|
| -/*
|
| - * Copyright (C) 2009 Google Inc. All rights reserved.
|
| - *
|
| - * Redistribution and use in source and binary forms, with or without
|
| - * modification, are permitted provided that the following conditions are
|
| - * met:
|
| - *
|
| - * * Redistributions of source code must retain the above copyright
|
| - * notice, this list of conditions and the following disclaimer.
|
| - * * Redistributions in binary form must reproduce the above
|
| - * copyright notice, this list of conditions and the following disclaimer
|
| - * in the documentation and/or other materials provided with the
|
| - * distribution.
|
| - * * Neither the name of Google Inc. nor the names of its
|
| - * contributors may be used to endorse or promote products derived from
|
| - * this software without specific prior written permission.
|
| - *
|
| - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| - * "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 THE COPYRIGHT
|
| - * OWNER 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.
|
| - */
|
| -
|
| -#include "config.h"
|
| -
|
| -#if ENABLE(SHARED_WORKERS)
|
| -
|
| -#include "DefaultSharedWorkerRepository.h"
|
| -
|
| -#include "ActiveDOMObject.h"
|
| -#include "CrossThreadTask.h"
|
| -#include "Document.h"
|
| -#include "ExceptionCode.h"
|
| -#include "InspectorInstrumentation.h"
|
| -#include "MessageEvent.h"
|
| -#include "MessagePort.h"
|
| -#include "NotImplemented.h"
|
| -#include "PageGroup.h"
|
| -#include "ScriptCallStack.h"
|
| -#include "SecurityOrigin.h"
|
| -#include "SecurityOriginHash.h"
|
| -#include "SharedWorker.h"
|
| -#include "SharedWorkerContext.h"
|
| -#include "SharedWorkerRepository.h"
|
| -#include "SharedWorkerThread.h"
|
| -#include "WorkerLoaderProxy.h"
|
| -#include "WorkerReportingProxy.h"
|
| -#include "WorkerScriptLoader.h"
|
| -#include "WorkerScriptLoaderClient.h"
|
| -#include <wtf/HashSet.h>
|
| -#include <wtf/Threading.h>
|
| -#include <wtf/text/WTFString.h>
|
| -
|
| -namespace WebCore {
|
| -
|
| -class SharedWorkerProxy : public ThreadSafeRefCounted<SharedWorkerProxy>, public WorkerLoaderProxy, public WorkerReportingProxy {
|
| -public:
|
| - static PassRefPtr<SharedWorkerProxy> create(const String& name, const KURL& url, PassRefPtr<SecurityOrigin> origin) { return adoptRef(new SharedWorkerProxy(name, url, origin)); }
|
| -
|
| - void setThread(PassRefPtr<SharedWorkerThread> thread) { m_thread = thread; }
|
| - SharedWorkerThread* thread() { return m_thread.get(); }
|
| - bool isClosing() const { return m_closing; }
|
| - KURL url() const
|
| - {
|
| - // Don't use m_url.copy() because it isn't a threadsafe method.
|
| - return KURL(ParsedURLString, m_url.string().isolatedCopy());
|
| - }
|
| -
|
| - String name() const { return m_name.isolatedCopy(); }
|
| - bool matches(const String& name, PassRefPtr<SecurityOrigin> origin, const KURL& urlToMatch) const;
|
| -
|
| - // WorkerLoaderProxy
|
| - virtual void postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task>);
|
| - virtual bool postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task>, const String&);
|
| -
|
| - // WorkerReportingProxy
|
| - virtual void postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL);
|
| - virtual void postConsoleMessageToWorkerObject(MessageSource, MessageLevel, const String& message, int lineNumber, const String& sourceURL);
|
| - virtual void postMessageToPageInspector(const String&);
|
| - virtual void updateInspectorStateCookie(const String&);
|
| - virtual void workerContextClosed();
|
| - virtual void workerContextDestroyed();
|
| -
|
| - // Updates the list of the worker's documents, per section 4.5 of the WebWorkers spec.
|
| - void addToWorkerDocuments(ScriptExecutionContext*);
|
| -
|
| - bool isInWorkerDocuments(Document* document) { return m_workerDocuments.contains(document); }
|
| -
|
| - // Removes a detached document from the list of worker's documents. May set the closing flag if this is the last document in the list.
|
| - void documentDetached(Document*);
|
| -
|
| - GroupSettings* groupSettings() const; // Page GroupSettings used by worker thread.
|
| -
|
| -private:
|
| - SharedWorkerProxy(const String& name, const KURL&, PassRefPtr<SecurityOrigin>);
|
| - void close();
|
| -
|
| - bool m_closing;
|
| - String m_name;
|
| - KURL m_url;
|
| - // The thread is freed when the proxy is destroyed, so we need to make sure that the proxy stays around until the SharedWorkerContext exits.
|
| - RefPtr<SharedWorkerThread> m_thread;
|
| - RefPtr<SecurityOrigin> m_origin;
|
| - HashSet<Document*> m_workerDocuments;
|
| - // Ensures exclusive access to the worker documents. Must not grab any other locks (such as the DefaultSharedWorkerRepository lock) while holding this one.
|
| - Mutex m_workerDocumentsLock;
|
| -};
|
| -
|
| -SharedWorkerProxy::SharedWorkerProxy(const String& name, const KURL& url, PassRefPtr<SecurityOrigin> origin)
|
| - : m_closing(false)
|
| - , m_name(name.isolatedCopy())
|
| - , m_url(url.copy())
|
| - , m_origin(origin)
|
| -{
|
| - // We should be the sole owner of the SecurityOrigin, as we will free it on another thread.
|
| - ASSERT(m_origin->hasOneRef());
|
| -}
|
| -
|
| -bool SharedWorkerProxy::matches(const String& name, PassRefPtr<SecurityOrigin> origin, const KURL& urlToMatch) const
|
| -{
|
| - // If the origins don't match, or the names don't match, then this is not the proxy we are looking for.
|
| - if (!origin->equal(m_origin.get()))
|
| - return false;
|
| -
|
| - // If the names are both empty, compares the URLs instead per the Web Workers spec.
|
| - if (name.isEmpty() && m_name.isEmpty())
|
| - return urlToMatch == url();
|
| -
|
| - return name == m_name;
|
| -}
|
| -
|
| -void SharedWorkerProxy::postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task> task)
|
| -{
|
| - MutexLocker lock(m_workerDocumentsLock);
|
| -
|
| - if (isClosing())
|
| - return;
|
| -
|
| - // If we aren't closing, then we must have at least one document.
|
| - ASSERT(m_workerDocuments.size());
|
| -
|
| - // Just pick an arbitrary active document from the HashSet and pass load requests to it.
|
| - // FIXME: Do we need to deal with the case where the user closes the document mid-load, via a shadow document or some other solution?
|
| - Document* document = *(m_workerDocuments.begin());
|
| - document->postTask(task);
|
| -}
|
| -
|
| -bool SharedWorkerProxy::postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
|
| -{
|
| - if (isClosing())
|
| - return false;
|
| - ASSERT(m_thread);
|
| - m_thread->runLoop().postTaskForMode(task, mode);
|
| - return true;
|
| -}
|
| -
|
| -GroupSettings* SharedWorkerProxy::groupSettings() const
|
| -{
|
| - if (isClosing())
|
| - return 0;
|
| - ASSERT(m_workerDocuments.size());
|
| - // Just pick the first active document, and use the groupsettings of that page.
|
| - Document* document = *(m_workerDocuments.begin());
|
| - if (document->page())
|
| - return document->page()->group().groupSettings();
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -static void postExceptionTask(ScriptExecutionContext* context, const String& errorMessage, int lineNumber, const String& sourceURL)
|
| -{
|
| - context->reportException(errorMessage, lineNumber, sourceURL, 0);
|
| -}
|
| -
|
| -void SharedWorkerProxy::postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL)
|
| -{
|
| - MutexLocker lock(m_workerDocumentsLock);
|
| - for (HashSet<Document*>::iterator iter = m_workerDocuments.begin(); iter != m_workerDocuments.end(); ++iter)
|
| - (*iter)->postTask(createCallbackTask(&postExceptionTask, errorMessage, lineNumber, sourceURL));
|
| -}
|
| -
|
| -static void postConsoleMessageTask(ScriptExecutionContext* document, MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber)
|
| -{
|
| - document->addConsoleMessage(source, level, message, sourceURL, lineNumber);
|
| -}
|
| -
|
| -void SharedWorkerProxy::postConsoleMessageToWorkerObject(MessageSource source, MessageLevel level, const String& message, int lineNumber, const String& sourceURL)
|
| -{
|
| - MutexLocker lock(m_workerDocumentsLock);
|
| - for (HashSet<Document*>::iterator iter = m_workerDocuments.begin(); iter != m_workerDocuments.end(); ++iter)
|
| - (*iter)->postTask(createCallbackTask(&postConsoleMessageTask, source, level, message, sourceURL, lineNumber));
|
| -}
|
| -
|
| -void SharedWorkerProxy::postMessageToPageInspector(const String&)
|
| -{
|
| - notImplemented();
|
| -}
|
| -
|
| -void SharedWorkerProxy::updateInspectorStateCookie(const String&)
|
| -{
|
| - notImplemented();
|
| -}
|
| -
|
| -void SharedWorkerProxy::workerContextClosed()
|
| -{
|
| - if (isClosing())
|
| - return;
|
| - close();
|
| -}
|
| -
|
| -void SharedWorkerProxy::workerContextDestroyed()
|
| -{
|
| - // The proxy may be freed by this call, so do not reference it any further.
|
| - DefaultSharedWorkerRepository::instance().removeProxy(this);
|
| -}
|
| -
|
| -void SharedWorkerProxy::addToWorkerDocuments(ScriptExecutionContext* context)
|
| -{
|
| - // Nested workers are not yet supported, so passed-in context should always be a Document.
|
| - ASSERT_WITH_SECURITY_IMPLICATION(context->isDocument());
|
| - ASSERT(!isClosing());
|
| - MutexLocker lock(m_workerDocumentsLock);
|
| - Document* document = static_cast<Document*>(context);
|
| - m_workerDocuments.add(document);
|
| -}
|
| -
|
| -void SharedWorkerProxy::documentDetached(Document* document)
|
| -{
|
| - if (isClosing())
|
| - return;
|
| - // Remove the document from our set (if it's there) and if that was the last document in the set, mark the proxy as closed.
|
| - MutexLocker lock(m_workerDocumentsLock);
|
| - m_workerDocuments.remove(document);
|
| - if (!m_workerDocuments.size())
|
| - close();
|
| -}
|
| -
|
| -void SharedWorkerProxy::close()
|
| -{
|
| - ASSERT(!isClosing());
|
| - m_closing = true;
|
| - // Stop the worker thread - the proxy will stay around until we get workerThreadExited() notification.
|
| - if (m_thread)
|
| - m_thread->stop();
|
| -}
|
| -
|
| -class SharedWorkerConnectTask : public ScriptExecutionContext::Task {
|
| -public:
|
| - static PassOwnPtr<SharedWorkerConnectTask> create(PassOwnPtr<MessagePortChannel> channel)
|
| - {
|
| - return adoptPtr(new SharedWorkerConnectTask(channel));
|
| - }
|
| -
|
| -private:
|
| - SharedWorkerConnectTask(PassOwnPtr<MessagePortChannel> channel)
|
| - : m_channel(channel)
|
| - {
|
| - }
|
| -
|
| - virtual void performTask(ScriptExecutionContext* scriptContext)
|
| - {
|
| - RefPtr<MessagePort> port = MessagePort::create(*scriptContext);
|
| - port->entangle(m_channel.release());
|
| - ASSERT_WITH_SECURITY_IMPLICATION(scriptContext->isWorkerContext());
|
| - WorkerContext* workerContext = static_cast<WorkerContext*>(scriptContext);
|
| - // Since close() stops the thread event loop, this should not ever get called while closing.
|
| - ASSERT(!workerContext->isClosing());
|
| - ASSERT_WITH_SECURITY_IMPLICATION(workerContext->isSharedWorkerContext());
|
| - workerContext->dispatchEvent(createConnectEvent(port));
|
| - }
|
| -
|
| - OwnPtr<MessagePortChannel> m_channel;
|
| -};
|
| -
|
| -// Loads the script on behalf of a worker.
|
| -class SharedWorkerScriptLoader : public RefCounted<SharedWorkerScriptLoader>, private WorkerScriptLoaderClient {
|
| -public:
|
| - SharedWorkerScriptLoader(PassRefPtr<SharedWorker>, PassOwnPtr<MessagePortChannel>, PassRefPtr<SharedWorkerProxy>);
|
| - void load(const KURL&);
|
| -
|
| -private:
|
| - // WorkerScriptLoaderClient callbacks
|
| - virtual void didReceiveResponse(unsigned long identifier, const ResourceResponse&);
|
| - virtual void notifyFinished();
|
| -
|
| - RefPtr<SharedWorker> m_worker;
|
| - OwnPtr<MessagePortChannel> m_port;
|
| - RefPtr<SharedWorkerProxy> m_proxy;
|
| - RefPtr<WorkerScriptLoader> m_scriptLoader;
|
| -};
|
| -
|
| -SharedWorkerScriptLoader::SharedWorkerScriptLoader(PassRefPtr<SharedWorker> worker, PassOwnPtr<MessagePortChannel> port, PassRefPtr<SharedWorkerProxy> proxy)
|
| - : m_worker(worker)
|
| - , m_port(port)
|
| - , m_proxy(proxy)
|
| -{
|
| -}
|
| -
|
| -void SharedWorkerScriptLoader::load(const KURL& url)
|
| -{
|
| - // Stay alive (and keep the SharedWorker and JS wrapper alive) until the load finishes.
|
| - this->ref();
|
| - m_worker->setPendingActivity(m_worker.get());
|
| -
|
| - // Mark this object as active for the duration of the load.
|
| - m_scriptLoader = WorkerScriptLoader::create();
|
| - m_scriptLoader->loadAsynchronously(m_worker->scriptExecutionContext(), url, DenyCrossOriginRequests, this);
|
| -}
|
| -
|
| -void SharedWorkerScriptLoader::didReceiveResponse(unsigned long identifier, const ResourceResponse&)
|
| -{
|
| - InspectorInstrumentation::didReceiveScriptResponse(m_worker->scriptExecutionContext(), identifier);
|
| -}
|
| -
|
| -void SharedWorkerScriptLoader::notifyFinished()
|
| -{
|
| - // FIXME: This method is not guaranteed to be invoked if we are loading from WorkerContext (see comment for WorkerScriptLoaderClient::notifyFinished()).
|
| - // We need to address this before supporting nested workers.
|
| -
|
| - // Hand off the just-loaded code to the repository to start up the worker thread.
|
| - if (m_scriptLoader->failed())
|
| - m_worker->dispatchEvent(Event::create(eventNames().errorEvent, false, true));
|
| - else {
|
| - InspectorInstrumentation::scriptImported(m_worker->scriptExecutionContext(), m_scriptLoader->identifier(), m_scriptLoader->script());
|
| - DefaultSharedWorkerRepository::instance().workerScriptLoaded(*m_proxy, m_worker->scriptExecutionContext()->userAgent(m_scriptLoader->url()),
|
| - m_scriptLoader->script(), m_port.release(),
|
| - m_worker->scriptExecutionContext()->contentSecurityPolicy()->deprecatedHeader(),
|
| - m_worker->scriptExecutionContext()->contentSecurityPolicy()->deprecatedHeaderType());
|
| - }
|
| - m_worker->unsetPendingActivity(m_worker.get());
|
| - this->deref(); // This frees this object - must be the last action in this function.
|
| -}
|
| -
|
| -DefaultSharedWorkerRepository& DefaultSharedWorkerRepository::instance()
|
| -{
|
| - AtomicallyInitializedStatic(DefaultSharedWorkerRepository*, instance = new DefaultSharedWorkerRepository);
|
| - return *instance;
|
| -}
|
| -
|
| -void DefaultSharedWorkerRepository::workerScriptLoaded(SharedWorkerProxy& proxy, const String& userAgent, const String& workerScript, PassOwnPtr<MessagePortChannel> port, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType)
|
| -{
|
| - MutexLocker lock(m_lock);
|
| - if (proxy.isClosing())
|
| - return;
|
| -
|
| - // Another loader may have already started up a thread for this proxy - if so, just send a connect to the pre-existing thread.
|
| - if (!proxy.thread()) {
|
| - RefPtr<SharedWorkerThread> thread = SharedWorkerThread::create(proxy.name(), proxy.url(), userAgent, proxy.groupSettings(), workerScript, proxy, proxy, DontPauseWorkerContextOnStart, contentSecurityPolicy, contentSecurityPolicyType);
|
| - proxy.setThread(thread);
|
| - thread->start();
|
| - }
|
| - proxy.thread()->runLoop().postTask(SharedWorkerConnectTask::create(port));
|
| -}
|
| -
|
| -bool DefaultSharedWorkerRepository::hasSharedWorkers(Document* document)
|
| -{
|
| - MutexLocker lock(m_lock);
|
| - for (unsigned i = 0; i < m_proxies.size(); i++) {
|
| - if (m_proxies[i]->isInWorkerDocuments(document))
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void DefaultSharedWorkerRepository::removeProxy(SharedWorkerProxy* proxy)
|
| -{
|
| - MutexLocker lock(m_lock);
|
| - for (unsigned i = 0; i < m_proxies.size(); i++) {
|
| - if (proxy == m_proxies[i].get()) {
|
| - m_proxies.remove(i);
|
| - return;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void DefaultSharedWorkerRepository::documentDetached(Document* document)
|
| -{
|
| - MutexLocker lock(m_lock);
|
| - for (unsigned i = 0; i < m_proxies.size(); i++)
|
| - m_proxies[i]->documentDetached(document);
|
| -}
|
| -
|
| -void DefaultSharedWorkerRepository::connectToWorker(PassRefPtr<SharedWorker> worker, PassOwnPtr<MessagePortChannel> port, const KURL& url, const String& name, ExceptionCode& ec)
|
| -{
|
| - MutexLocker lock(m_lock);
|
| - ASSERT(worker->scriptExecutionContext()->securityOrigin()->canAccess(SecurityOrigin::create(url).get()));
|
| - // Fetch a proxy corresponding to this SharedWorker.
|
| - RefPtr<SharedWorkerProxy> proxy = getProxy(name, url);
|
| -
|
| - // FIXME: Why is this done even if we are raising an exception below?
|
| - proxy->addToWorkerDocuments(worker->scriptExecutionContext());
|
| -
|
| - if (proxy->url() != url) {
|
| - // Proxy already existed under alternate URL - return an error.
|
| - ec = URL_MISMATCH_ERR;
|
| - return;
|
| - }
|
| - // If proxy is already running, just connect to it - otherwise, kick off a loader to load the script.
|
| - if (proxy->thread())
|
| - proxy->thread()->runLoop().postTask(SharedWorkerConnectTask::create(port));
|
| - else {
|
| - RefPtr<SharedWorkerScriptLoader> loader = adoptRef(new SharedWorkerScriptLoader(worker, port, proxy.release()));
|
| - loader->load(url);
|
| - }
|
| -}
|
| -
|
| -// Creates a new SharedWorkerProxy or returns an existing one from the repository. Must only be called while the repository mutex is held.
|
| -PassRefPtr<SharedWorkerProxy> DefaultSharedWorkerRepository::getProxy(const String& name, const KURL& url)
|
| -{
|
| - // Look for an existing worker, and create one if it doesn't exist.
|
| - // Items in the cache are freed on another thread, so do a threadsafe copy of the URL before creating the origin,
|
| - // to make sure no references to external strings linger.
|
| - RefPtr<SecurityOrigin> origin = SecurityOrigin::create(KURL(ParsedURLString, url.string().isolatedCopy()));
|
| - for (unsigned i = 0; i < m_proxies.size(); i++) {
|
| - if (!m_proxies[i]->isClosing() && m_proxies[i]->matches(name, origin, url))
|
| - return m_proxies[i];
|
| - }
|
| - // Proxy is not in the repository currently - create a new one.
|
| - RefPtr<SharedWorkerProxy> proxy = SharedWorkerProxy::create(name, url, origin.release());
|
| - m_proxies.append(proxy);
|
| - return proxy.release();
|
| -}
|
| -
|
| -DefaultSharedWorkerRepository::DefaultSharedWorkerRepository()
|
| -{
|
| -}
|
| -
|
| -DefaultSharedWorkerRepository::~DefaultSharedWorkerRepository()
|
| -{
|
| -}
|
| -
|
| -} // namespace WebCore
|
| -
|
| -#endif // ENABLE(SHARED_WORKERS)
|
|
|