| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2009 Google 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 are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #include "config.h" | |
| 32 | |
| 33 #if ENABLE(SHARED_WORKERS) | |
| 34 | |
| 35 #include "DefaultSharedWorkerRepository.h" | |
| 36 | |
| 37 #include "ActiveDOMObject.h" | |
| 38 #include "CrossThreadTask.h" | |
| 39 #include "Document.h" | |
| 40 #include "ExceptionCode.h" | |
| 41 #include "InspectorInstrumentation.h" | |
| 42 #include "MessageEvent.h" | |
| 43 #include "MessagePort.h" | |
| 44 #include "NotImplemented.h" | |
| 45 #include "PageGroup.h" | |
| 46 #include "ScriptCallStack.h" | |
| 47 #include "SecurityOrigin.h" | |
| 48 #include "SecurityOriginHash.h" | |
| 49 #include "SharedWorker.h" | |
| 50 #include "SharedWorkerContext.h" | |
| 51 #include "SharedWorkerRepository.h" | |
| 52 #include "SharedWorkerThread.h" | |
| 53 #include "WorkerLoaderProxy.h" | |
| 54 #include "WorkerReportingProxy.h" | |
| 55 #include "WorkerScriptLoader.h" | |
| 56 #include "WorkerScriptLoaderClient.h" | |
| 57 #include <wtf/HashSet.h> | |
| 58 #include <wtf/Threading.h> | |
| 59 #include <wtf/text/WTFString.h> | |
| 60 | |
| 61 namespace WebCore { | |
| 62 | |
| 63 class SharedWorkerProxy : public ThreadSafeRefCounted<SharedWorkerProxy>, public
WorkerLoaderProxy, public WorkerReportingProxy { | |
| 64 public: | |
| 65 static PassRefPtr<SharedWorkerProxy> create(const String& name, const KURL&
url, PassRefPtr<SecurityOrigin> origin) { return adoptRef(new SharedWorkerProxy(
name, url, origin)); } | |
| 66 | |
| 67 void setThread(PassRefPtr<SharedWorkerThread> thread) { m_thread = thread; } | |
| 68 SharedWorkerThread* thread() { return m_thread.get(); } | |
| 69 bool isClosing() const { return m_closing; } | |
| 70 KURL url() const | |
| 71 { | |
| 72 // Don't use m_url.copy() because it isn't a threadsafe method. | |
| 73 return KURL(ParsedURLString, m_url.string().isolatedCopy()); | |
| 74 } | |
| 75 | |
| 76 String name() const { return m_name.isolatedCopy(); } | |
| 77 bool matches(const String& name, PassRefPtr<SecurityOrigin> origin, const KU
RL& urlToMatch) const; | |
| 78 | |
| 79 // WorkerLoaderProxy | |
| 80 virtual void postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task>); | |
| 81 virtual bool postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContex
t::Task>, const String&); | |
| 82 | |
| 83 // WorkerReportingProxy | |
| 84 virtual void postExceptionToWorkerObject(const String& errorMessage, int lin
eNumber, const String& sourceURL); | |
| 85 virtual void postConsoleMessageToWorkerObject(MessageSource, MessageLevel, c
onst String& message, int lineNumber, const String& sourceURL); | |
| 86 virtual void postMessageToPageInspector(const String&); | |
| 87 virtual void updateInspectorStateCookie(const String&); | |
| 88 virtual void workerContextClosed(); | |
| 89 virtual void workerContextDestroyed(); | |
| 90 | |
| 91 // Updates the list of the worker's documents, per section 4.5 of the WebWor
kers spec. | |
| 92 void addToWorkerDocuments(ScriptExecutionContext*); | |
| 93 | |
| 94 bool isInWorkerDocuments(Document* document) { return m_workerDocuments.cont
ains(document); } | |
| 95 | |
| 96 // 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. | |
| 97 void documentDetached(Document*); | |
| 98 | |
| 99 GroupSettings* groupSettings() const; // Page GroupSettings used by worker t
hread. | |
| 100 | |
| 101 private: | |
| 102 SharedWorkerProxy(const String& name, const KURL&, PassRefPtr<SecurityOrigin
>); | |
| 103 void close(); | |
| 104 | |
| 105 bool m_closing; | |
| 106 String m_name; | |
| 107 KURL m_url; | |
| 108 // The thread is freed when the proxy is destroyed, so we need to make sure
that the proxy stays around until the SharedWorkerContext exits. | |
| 109 RefPtr<SharedWorkerThread> m_thread; | |
| 110 RefPtr<SecurityOrigin> m_origin; | |
| 111 HashSet<Document*> m_workerDocuments; | |
| 112 // Ensures exclusive access to the worker documents. Must not grab any other
locks (such as the DefaultSharedWorkerRepository lock) while holding this one. | |
| 113 Mutex m_workerDocumentsLock; | |
| 114 }; | |
| 115 | |
| 116 SharedWorkerProxy::SharedWorkerProxy(const String& name, const KURL& url, PassRe
fPtr<SecurityOrigin> origin) | |
| 117 : m_closing(false) | |
| 118 , m_name(name.isolatedCopy()) | |
| 119 , m_url(url.copy()) | |
| 120 , m_origin(origin) | |
| 121 { | |
| 122 // We should be the sole owner of the SecurityOrigin, as we will free it on
another thread. | |
| 123 ASSERT(m_origin->hasOneRef()); | |
| 124 } | |
| 125 | |
| 126 bool SharedWorkerProxy::matches(const String& name, PassRefPtr<SecurityOrigin> o
rigin, const KURL& urlToMatch) const | |
| 127 { | |
| 128 // If the origins don't match, or the names don't match, then this is not th
e proxy we are looking for. | |
| 129 if (!origin->equal(m_origin.get())) | |
| 130 return false; | |
| 131 | |
| 132 // If the names are both empty, compares the URLs instead per the Web Worker
s spec. | |
| 133 if (name.isEmpty() && m_name.isEmpty()) | |
| 134 return urlToMatch == url(); | |
| 135 | |
| 136 return name == m_name; | |
| 137 } | |
| 138 | |
| 139 void SharedWorkerProxy::postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task
> task) | |
| 140 { | |
| 141 MutexLocker lock(m_workerDocumentsLock); | |
| 142 | |
| 143 if (isClosing()) | |
| 144 return; | |
| 145 | |
| 146 // If we aren't closing, then we must have at least one document. | |
| 147 ASSERT(m_workerDocuments.size()); | |
| 148 | |
| 149 // Just pick an arbitrary active document from the HashSet and pass load req
uests to it. | |
| 150 // FIXME: Do we need to deal with the case where the user closes the documen
t mid-load, via a shadow document or some other solution? | |
| 151 Document* document = *(m_workerDocuments.begin()); | |
| 152 document->postTask(task); | |
| 153 } | |
| 154 | |
| 155 bool SharedWorkerProxy::postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutio
nContext::Task> task, const String& mode) | |
| 156 { | |
| 157 if (isClosing()) | |
| 158 return false; | |
| 159 ASSERT(m_thread); | |
| 160 m_thread->runLoop().postTaskForMode(task, mode); | |
| 161 return true; | |
| 162 } | |
| 163 | |
| 164 GroupSettings* SharedWorkerProxy::groupSettings() const | |
| 165 { | |
| 166 if (isClosing()) | |
| 167 return 0; | |
| 168 ASSERT(m_workerDocuments.size()); | |
| 169 // Just pick the first active document, and use the groupsettings of that pa
ge. | |
| 170 Document* document = *(m_workerDocuments.begin()); | |
| 171 if (document->page()) | |
| 172 return document->page()->group().groupSettings(); | |
| 173 | |
| 174 return 0; | |
| 175 } | |
| 176 | |
| 177 static void postExceptionTask(ScriptExecutionContext* context, const String& err
orMessage, int lineNumber, const String& sourceURL) | |
| 178 { | |
| 179 context->reportException(errorMessage, lineNumber, sourceURL, 0); | |
| 180 } | |
| 181 | |
| 182 void SharedWorkerProxy::postExceptionToWorkerObject(const String& errorMessage,
int lineNumber, const String& sourceURL) | |
| 183 { | |
| 184 MutexLocker lock(m_workerDocumentsLock); | |
| 185 for (HashSet<Document*>::iterator iter = m_workerDocuments.begin(); iter !=
m_workerDocuments.end(); ++iter) | |
| 186 (*iter)->postTask(createCallbackTask(&postExceptionTask, errorMessage, l
ineNumber, sourceURL)); | |
| 187 } | |
| 188 | |
| 189 static void postConsoleMessageTask(ScriptExecutionContext* document, MessageSour
ce source, MessageLevel level, const String& message, const String& sourceURL, u
nsigned lineNumber) | |
| 190 { | |
| 191 document->addConsoleMessage(source, level, message, sourceURL, lineNumber); | |
| 192 } | |
| 193 | |
| 194 void SharedWorkerProxy::postConsoleMessageToWorkerObject(MessageSource source, M
essageLevel level, const String& message, int lineNumber, const String& sourceUR
L) | |
| 195 { | |
| 196 MutexLocker lock(m_workerDocumentsLock); | |
| 197 for (HashSet<Document*>::iterator iter = m_workerDocuments.begin(); iter !=
m_workerDocuments.end(); ++iter) | |
| 198 (*iter)->postTask(createCallbackTask(&postConsoleMessageTask, source, le
vel, message, sourceURL, lineNumber)); | |
| 199 } | |
| 200 | |
| 201 void SharedWorkerProxy::postMessageToPageInspector(const String&) | |
| 202 { | |
| 203 notImplemented(); | |
| 204 } | |
| 205 | |
| 206 void SharedWorkerProxy::updateInspectorStateCookie(const String&) | |
| 207 { | |
| 208 notImplemented(); | |
| 209 } | |
| 210 | |
| 211 void SharedWorkerProxy::workerContextClosed() | |
| 212 { | |
| 213 if (isClosing()) | |
| 214 return; | |
| 215 close(); | |
| 216 } | |
| 217 | |
| 218 void SharedWorkerProxy::workerContextDestroyed() | |
| 219 { | |
| 220 // The proxy may be freed by this call, so do not reference it any further. | |
| 221 DefaultSharedWorkerRepository::instance().removeProxy(this); | |
| 222 } | |
| 223 | |
| 224 void SharedWorkerProxy::addToWorkerDocuments(ScriptExecutionContext* context) | |
| 225 { | |
| 226 // Nested workers are not yet supported, so passed-in context should always
be a Document. | |
| 227 ASSERT_WITH_SECURITY_IMPLICATION(context->isDocument()); | |
| 228 ASSERT(!isClosing()); | |
| 229 MutexLocker lock(m_workerDocumentsLock); | |
| 230 Document* document = static_cast<Document*>(context); | |
| 231 m_workerDocuments.add(document); | |
| 232 } | |
| 233 | |
| 234 void SharedWorkerProxy::documentDetached(Document* document) | |
| 235 { | |
| 236 if (isClosing()) | |
| 237 return; | |
| 238 // 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. | |
| 239 MutexLocker lock(m_workerDocumentsLock); | |
| 240 m_workerDocuments.remove(document); | |
| 241 if (!m_workerDocuments.size()) | |
| 242 close(); | |
| 243 } | |
| 244 | |
| 245 void SharedWorkerProxy::close() | |
| 246 { | |
| 247 ASSERT(!isClosing()); | |
| 248 m_closing = true; | |
| 249 // Stop the worker thread - the proxy will stay around until we get workerTh
readExited() notification. | |
| 250 if (m_thread) | |
| 251 m_thread->stop(); | |
| 252 } | |
| 253 | |
| 254 class SharedWorkerConnectTask : public ScriptExecutionContext::Task { | |
| 255 public: | |
| 256 static PassOwnPtr<SharedWorkerConnectTask> create(PassOwnPtr<MessagePortChan
nel> channel) | |
| 257 { | |
| 258 return adoptPtr(new SharedWorkerConnectTask(channel)); | |
| 259 } | |
| 260 | |
| 261 private: | |
| 262 SharedWorkerConnectTask(PassOwnPtr<MessagePortChannel> channel) | |
| 263 : m_channel(channel) | |
| 264 { | |
| 265 } | |
| 266 | |
| 267 virtual void performTask(ScriptExecutionContext* scriptContext) | |
| 268 { | |
| 269 RefPtr<MessagePort> port = MessagePort::create(*scriptContext); | |
| 270 port->entangle(m_channel.release()); | |
| 271 ASSERT_WITH_SECURITY_IMPLICATION(scriptContext->isWorkerContext()); | |
| 272 WorkerContext* workerContext = static_cast<WorkerContext*>(scriptContext
); | |
| 273 // Since close() stops the thread event loop, this should not ever get c
alled while closing. | |
| 274 ASSERT(!workerContext->isClosing()); | |
| 275 ASSERT_WITH_SECURITY_IMPLICATION(workerContext->isSharedWorkerContext())
; | |
| 276 workerContext->dispatchEvent(createConnectEvent(port)); | |
| 277 } | |
| 278 | |
| 279 OwnPtr<MessagePortChannel> m_channel; | |
| 280 }; | |
| 281 | |
| 282 // Loads the script on behalf of a worker. | |
| 283 class SharedWorkerScriptLoader : public RefCounted<SharedWorkerScriptLoader>, pr
ivate WorkerScriptLoaderClient { | |
| 284 public: | |
| 285 SharedWorkerScriptLoader(PassRefPtr<SharedWorker>, PassOwnPtr<MessagePortCha
nnel>, PassRefPtr<SharedWorkerProxy>); | |
| 286 void load(const KURL&); | |
| 287 | |
| 288 private: | |
| 289 // WorkerScriptLoaderClient callbacks | |
| 290 virtual void didReceiveResponse(unsigned long identifier, const ResourceResp
onse&); | |
| 291 virtual void notifyFinished(); | |
| 292 | |
| 293 RefPtr<SharedWorker> m_worker; | |
| 294 OwnPtr<MessagePortChannel> m_port; | |
| 295 RefPtr<SharedWorkerProxy> m_proxy; | |
| 296 RefPtr<WorkerScriptLoader> m_scriptLoader; | |
| 297 }; | |
| 298 | |
| 299 SharedWorkerScriptLoader::SharedWorkerScriptLoader(PassRefPtr<SharedWorker> work
er, PassOwnPtr<MessagePortChannel> port, PassRefPtr<SharedWorkerProxy> proxy) | |
| 300 : m_worker(worker) | |
| 301 , m_port(port) | |
| 302 , m_proxy(proxy) | |
| 303 { | |
| 304 } | |
| 305 | |
| 306 void SharedWorkerScriptLoader::load(const KURL& url) | |
| 307 { | |
| 308 // Stay alive (and keep the SharedWorker and JS wrapper alive) until the loa
d finishes. | |
| 309 this->ref(); | |
| 310 m_worker->setPendingActivity(m_worker.get()); | |
| 311 | |
| 312 // Mark this object as active for the duration of the load. | |
| 313 m_scriptLoader = WorkerScriptLoader::create(); | |
| 314 m_scriptLoader->loadAsynchronously(m_worker->scriptExecutionContext(), url,
DenyCrossOriginRequests, this); | |
| 315 } | |
| 316 | |
| 317 void SharedWorkerScriptLoader::didReceiveResponse(unsigned long identifier, cons
t ResourceResponse&) | |
| 318 { | |
| 319 InspectorInstrumentation::didReceiveScriptResponse(m_worker->scriptExecution
Context(), identifier); | |
| 320 } | |
| 321 | |
| 322 void SharedWorkerScriptLoader::notifyFinished() | |
| 323 { | |
| 324 // FIXME: This method is not guaranteed to be invoked if we are loading from
WorkerContext (see comment for WorkerScriptLoaderClient::notifyFinished()). | |
| 325 // We need to address this before supporting nested workers. | |
| 326 | |
| 327 // Hand off the just-loaded code to the repository to start up the worker th
read. | |
| 328 if (m_scriptLoader->failed()) | |
| 329 m_worker->dispatchEvent(Event::create(eventNames().errorEvent, false, tr
ue)); | |
| 330 else { | |
| 331 InspectorInstrumentation::scriptImported(m_worker->scriptExecutionContex
t(), m_scriptLoader->identifier(), m_scriptLoader->script()); | |
| 332 DefaultSharedWorkerRepository::instance().workerScriptLoaded(*m_proxy, m
_worker->scriptExecutionContext()->userAgent(m_scriptLoader->url()), | |
| 333 m_scriptLoa
der->script(), m_port.release(), | |
| 334 m_worker->s
criptExecutionContext()->contentSecurityPolicy()->deprecatedHeader(), | |
| 335 m_worker->s
criptExecutionContext()->contentSecurityPolicy()->deprecatedHeaderType()); | |
| 336 } | |
| 337 m_worker->unsetPendingActivity(m_worker.get()); | |
| 338 this->deref(); // This frees this object - must be the last action in this f
unction. | |
| 339 } | |
| 340 | |
| 341 DefaultSharedWorkerRepository& DefaultSharedWorkerRepository::instance() | |
| 342 { | |
| 343 AtomicallyInitializedStatic(DefaultSharedWorkerRepository*, instance = new D
efaultSharedWorkerRepository); | |
| 344 return *instance; | |
| 345 } | |
| 346 | |
| 347 void DefaultSharedWorkerRepository::workerScriptLoaded(SharedWorkerProxy& proxy,
const String& userAgent, const String& workerScript, PassOwnPtr<MessagePortChan
nel> port, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderTyp
e contentSecurityPolicyType) | |
| 348 { | |
| 349 MutexLocker lock(m_lock); | |
| 350 if (proxy.isClosing()) | |
| 351 return; | |
| 352 | |
| 353 // Another loader may have already started up a thread for this proxy - if s
o, just send a connect to the pre-existing thread. | |
| 354 if (!proxy.thread()) { | |
| 355 RefPtr<SharedWorkerThread> thread = SharedWorkerThread::create(proxy.nam
e(), proxy.url(), userAgent, proxy.groupSettings(), workerScript, proxy, proxy,
DontPauseWorkerContextOnStart, contentSecurityPolicy, contentSecurityPolicyType)
; | |
| 356 proxy.setThread(thread); | |
| 357 thread->start(); | |
| 358 } | |
| 359 proxy.thread()->runLoop().postTask(SharedWorkerConnectTask::create(port)); | |
| 360 } | |
| 361 | |
| 362 bool DefaultSharedWorkerRepository::hasSharedWorkers(Document* document) | |
| 363 { | |
| 364 MutexLocker lock(m_lock); | |
| 365 for (unsigned i = 0; i < m_proxies.size(); i++) { | |
| 366 if (m_proxies[i]->isInWorkerDocuments(document)) | |
| 367 return true; | |
| 368 } | |
| 369 return false; | |
| 370 } | |
| 371 | |
| 372 void DefaultSharedWorkerRepository::removeProxy(SharedWorkerProxy* proxy) | |
| 373 { | |
| 374 MutexLocker lock(m_lock); | |
| 375 for (unsigned i = 0; i < m_proxies.size(); i++) { | |
| 376 if (proxy == m_proxies[i].get()) { | |
| 377 m_proxies.remove(i); | |
| 378 return; | |
| 379 } | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 void DefaultSharedWorkerRepository::documentDetached(Document* document) | |
| 384 { | |
| 385 MutexLocker lock(m_lock); | |
| 386 for (unsigned i = 0; i < m_proxies.size(); i++) | |
| 387 m_proxies[i]->documentDetached(document); | |
| 388 } | |
| 389 | |
| 390 void DefaultSharedWorkerRepository::connectToWorker(PassRefPtr<SharedWorker> wor
ker, PassOwnPtr<MessagePortChannel> port, const KURL& url, const String& name, E
xceptionCode& ec) | |
| 391 { | |
| 392 MutexLocker lock(m_lock); | |
| 393 ASSERT(worker->scriptExecutionContext()->securityOrigin()->canAccess(Securit
yOrigin::create(url).get())); | |
| 394 // Fetch a proxy corresponding to this SharedWorker. | |
| 395 RefPtr<SharedWorkerProxy> proxy = getProxy(name, url); | |
| 396 | |
| 397 // FIXME: Why is this done even if we are raising an exception below? | |
| 398 proxy->addToWorkerDocuments(worker->scriptExecutionContext()); | |
| 399 | |
| 400 if (proxy->url() != url) { | |
| 401 // Proxy already existed under alternate URL - return an error. | |
| 402 ec = URL_MISMATCH_ERR; | |
| 403 return; | |
| 404 } | |
| 405 // If proxy is already running, just connect to it - otherwise, kick off a l
oader to load the script. | |
| 406 if (proxy->thread()) | |
| 407 proxy->thread()->runLoop().postTask(SharedWorkerConnectTask::create(port
)); | |
| 408 else { | |
| 409 RefPtr<SharedWorkerScriptLoader> loader = adoptRef(new SharedWorkerScrip
tLoader(worker, port, proxy.release())); | |
| 410 loader->load(url); | |
| 411 } | |
| 412 } | |
| 413 | |
| 414 // Creates a new SharedWorkerProxy or returns an existing one from the repositor
y. Must only be called while the repository mutex is held. | |
| 415 PassRefPtr<SharedWorkerProxy> DefaultSharedWorkerRepository::getProxy(const Stri
ng& name, const KURL& url) | |
| 416 { | |
| 417 // Look for an existing worker, and create one if it doesn't exist. | |
| 418 // Items in the cache are freed on another thread, so do a threadsafe copy o
f the URL before creating the origin, | |
| 419 // to make sure no references to external strings linger. | |
| 420 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(KURL(ParsedURLString,
url.string().isolatedCopy())); | |
| 421 for (unsigned i = 0; i < m_proxies.size(); i++) { | |
| 422 if (!m_proxies[i]->isClosing() && m_proxies[i]->matches(name, origin, ur
l)) | |
| 423 return m_proxies[i]; | |
| 424 } | |
| 425 // Proxy is not in the repository currently - create a new one. | |
| 426 RefPtr<SharedWorkerProxy> proxy = SharedWorkerProxy::create(name, url, origi
n.release()); | |
| 427 m_proxies.append(proxy); | |
| 428 return proxy.release(); | |
| 429 } | |
| 430 | |
| 431 DefaultSharedWorkerRepository::DefaultSharedWorkerRepository() | |
| 432 { | |
| 433 } | |
| 434 | |
| 435 DefaultSharedWorkerRepository::~DefaultSharedWorkerRepository() | |
| 436 { | |
| 437 } | |
| 438 | |
| 439 } // namespace WebCore | |
| 440 | |
| 441 #endif // ENABLE(SHARED_WORKERS) | |
| OLD | NEW |