From ab3505360bf6612d18915a39a0fec74b00642e82 Mon Sep 17 00:00:00 2001
From: "atwilson@chromium.org"
 <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Fri, 30 Oct 2009 18:11:47 +0000
Subject: Initial pass of shared workers renderer-side code

Added initial interface hooks betweek WebKit code and renderer-side worker code.
The proper messages are generated to fire off a shared worker, but they are currently
ignored by the browser process.

BUG=26233
TEST=none (will enable layout tests when basic functionality available)

Review URL: http://codereview.chromium.org/340036

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30599 0039d316-1c4b-4281-b951-d872f2087c98
---
 .../in_process_webkit/browser_webkitclient_impl.cc |   6 ++
 .../in_process_webkit/browser_webkitclient_impl.h  |   1 +
 chrome/browser/worker_host/worker_process_host.cc  |  78 ++++++++++------
 chrome/chrome.gyp                                  |   6 ++
 chrome/common/render_messages_internal.h           |  18 +++-
 chrome/common/worker_messages_internal.h           |   4 +
 chrome/renderer/renderer_webkitclient_impl.cc      |   5 +
 chrome/renderer/renderer_webkitclient_impl.h       |   8 ++
 chrome/renderer/websharedworker_impl.cc            |  58 ++++++++++++
 chrome/renderer/websharedworker_impl.h             |  49 ++++++++++
 chrome/renderer/websharedworkerrepository_impl.cc  |  24 +++++
 chrome/renderer/websharedworkerrepository_impl.h   |  22 +++++
 chrome/renderer/webworker_base.cc                  | 102 +++++++++++++++++++++
 chrome/renderer/webworker_base.h                   |  64 +++++++++++++
 chrome/renderer/webworker_proxy.cc                 |  69 +++-----------
 chrome/renderer/webworker_proxy.h                  |  21 +----
 chrome/worker/worker_webkitclient_impl.cc          |   5 +
 chrome/worker/worker_webkitclient_impl.h           |   1 +
 18 files changed, 434 insertions(+), 107 deletions(-)
 create mode 100644 chrome/renderer/websharedworker_impl.cc
 create mode 100644 chrome/renderer/websharedworker_impl.h
 create mode 100644 chrome/renderer/websharedworkerrepository_impl.cc
 create mode 100644 chrome/renderer/websharedworkerrepository_impl.h
 create mode 100644 chrome/renderer/webworker_base.cc
 create mode 100644 chrome/renderer/webworker_base.h

(limited to 'chrome')

diff --git a/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc b/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
index 6a13013..ec893fb 100644
--- a/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
+++ b/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
@@ -123,3 +123,9 @@ void BrowserWebKitClientImpl::dispatchStorageEvent(
   DOMStorageDispatcherHost::DispatchStorageEvent(key, old_value, new_value,
                                                  origin, is_local_storage);
 }
+
+WebKit::WebSharedWorkerRepository*
+BrowserWebKitClientImpl::sharedWorkerRepository() {
+    NOTREACHED();
+    return NULL;
+}
diff --git a/chrome/browser/in_process_webkit/browser_webkitclient_impl.h b/chrome/browser/in_process_webkit/browser_webkitclient_impl.h
index 0024bfb..ff79350 100644
--- a/chrome/browser/in_process_webkit/browser_webkitclient_impl.h
+++ b/chrome/browser/in_process_webkit/browser_webkitclient_impl.h
@@ -36,6 +36,7 @@ class BrowserWebKitClientImpl : public webkit_glue::WebKitClientImpl {
   virtual void dispatchStorageEvent(const WebKit::WebString& key,
       const WebKit::WebString& oldValue, const WebKit::WebString& newValue,
       const WebKit::WebString& origin, bool isLocalStorage);
+  virtual WebKit::WebSharedWorkerRepository* sharedWorkerRepository();
 };
 
 #endif  // CHROME_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_CLIENT_IMPL_H_
diff --git a/chrome/browser/worker_host/worker_process_host.cc b/chrome/browser/worker_host/worker_process_host.cc
index 094a2fd..54446b3 100644
--- a/chrome/browser/worker_host/worker_process_host.cc
+++ b/chrome/browser/worker_host/worker_process_host.cc
@@ -144,7 +144,7 @@ void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
 
   UpdateTitle();
   instances_.back().sender->Send(
-      new ViewMsg_DedicatedWorkerCreated(instance.sender_route_id));
+      new ViewMsg_WorkerCreated(instance.sender_route_id));
 }
 
 bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
@@ -229,39 +229,59 @@ void WorkerProcessHost::RelayMessage(
     IPC::Message::Sender* sender,
     int route_id,
     CallbackWithReturnValue<int>::Type* next_route_id) {
-  if (message.type() != WorkerMsg_PostMessage::ID) {
-    IPC::Message* new_message = new IPC::Message(message);
-    new_message->set_routing_id(route_id);
-    sender->Send(new_message);
-    return;
-  }
 
-  // We want to send the receiver a routing id for the new channel, so
-  // crack the message first.
-  string16 msg;
-  std::vector<int> sent_message_port_ids;
-  std::vector<int> new_routing_ids;
-  if (!WorkerMsg_PostMessage::Read(
-          &message, &msg, &sent_message_port_ids, &new_routing_ids)) {
-    return;
-  }
-  DCHECK(sent_message_port_ids.size() == new_routing_ids.size());
+  if (message.type() == WorkerMsg_PostMessage::ID) {
+    // We want to send the receiver a routing id for the new channel, so
+    // crack the message first.
+    string16 msg;
+    std::vector<int> sent_message_port_ids;
+    std::vector<int> new_routing_ids;
+    if (!WorkerMsg_PostMessage::Read(
+            &message, &msg, &sent_message_port_ids, &new_routing_ids)) {
+      return;
+    }
+    DCHECK(sent_message_port_ids.size() == new_routing_ids.size());
+
+    for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
+      new_routing_ids[i] = next_route_id->Run();
+      MessagePortDispatcher::GetInstance()->UpdateMessagePort(
+          sent_message_port_ids[i], sender, new_routing_ids[i], next_route_id);
+    }
+
+    sender->Send(new WorkerMsg_PostMessage(
+        route_id, msg, sent_message_port_ids, new_routing_ids));
 
-  for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
-    new_routing_ids[i] = next_route_id->Run();
+    // Send any queued messages to the sent message ports.  We can only do this
+    // after sending the above message, since it's the one that sets up the
+    // message port route which the queued messages are sent to.
+    for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
+      MessagePortDispatcher::GetInstance()->
+          SendQueuedMessagesIfPossible(sent_message_port_ids[i]);
+    }
+  } else if (message.type() == WorkerMsg_Connect::ID) {
+    // Crack the SharedWorker Connect message to setup routing for the port.
+    int sent_message_port_id;
+    int new_routing_id;
+    if (!WorkerMsg_Connect::Read(
+            &message, &sent_message_port_id, &new_routing_id)) {
+      return;
+    }
+    new_routing_id = next_route_id->Run();
     MessagePortDispatcher::GetInstance()->UpdateMessagePort(
-        sent_message_port_ids[i], sender, new_routing_ids[i], next_route_id);
-  }
+        sent_message_port_id, sender, new_routing_id, next_route_id);
 
-  sender->Send(new WorkerMsg_PostMessage(
-      route_id, msg, sent_message_port_ids, new_routing_ids));
+    // Resend the message with the new routing id.
+    sender->Send(new WorkerMsg_Connect(
+        route_id, sent_message_port_id, new_routing_id));
 
-  // Send any queued messages to the sent message ports.  We can only do this
-  // after sending the above message, since it's the one that sets up the
-  // message port route which the queued messages are sent to.
-  for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
-    MessagePortDispatcher::GetInstance()->
-        SendQueuedMessagesIfPossible(sent_message_port_ids[i]);
+    // Send any queued messages for the sent port.
+    MessagePortDispatcher::GetInstance()->SendQueuedMessagesIfPossible(
+        sent_message_port_id);
+  } else {
+    IPC::Message* new_message = new IPC::Message(message);
+    new_message->set_routing_id(route_id);
+    sender->Send(new_message);
+    return;
   }
 }
 
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 91fcfab..32ecdb5 100755
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -3306,6 +3306,12 @@
         'renderer/webplugin_delegate_proxy.h',
         'renderer/webplugin_delegate_pepper.cc',
         'renderer/webplugin_delegate_pepper.h',
+        'renderer/websharedworker_impl.cc',
+        'renderer/websharedworker_impl.h',
+        'renderer/websharedworkerrepository_impl.cc',
+        'renderer/websharedworkerrepository_impl.h',
+        'renderer/webworker_base.cc',
+        'renderer/webworker_base.h',
         'renderer/webworker_proxy.cc',
         'renderer/webworker_proxy.h',
       ],
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index cecc9fc6..81f9c1f 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -720,9 +720,9 @@ IPC_BEGIN_MESSAGES(View)
   IPC_MESSAGE_ROUTED1(ViewMsg_SetActive,
                       bool /* active */)
 
-  // Response message to ViewHostMsg_CreateDedicatedWorker.  Sent when the
-  // worker has started.
-  IPC_MESSAGE_ROUTED0(ViewMsg_DedicatedWorkerCreated)
+  // Response message to ViewHostMsg_CreateShared/DedicatedWorker.
+  // Sent when the worker has started.
+  IPC_MESSAGE_ROUTED0(ViewMsg_WorkerCreated)
 
   // Tell the renderer which browser window it's being attached to.
   IPC_MESSAGE_ROUTED1(ViewMsg_UpdateBrowserWindowId,
@@ -1710,6 +1710,16 @@ IPC_BEGIN_MESSAGES(ViewHost)
                               int /* render_view_route_id */,
                               int /* route_id */)
 
+  // A renderer sends this to the browser process when it wants to create a
+  // shared worker.  The browser will create the worker process if necessary,
+  // and will return the route id on success.  On error returns
+  // MSG_ROUTING_NONE.
+  IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_CreateSharedWorker,
+                              GURL /* url */,
+                              string16 /* name */,
+                              int /* render_view_route_id */,
+                              int /* route_id */)
+
   // A message sent to the browser on behalf of a renderer which wants to show
   // a desktop notification.
   IPC_MESSAGE_ROUTED3(ViewHostMsg_ShowDesktopNotification,
@@ -1732,7 +1742,7 @@ IPC_BEGIN_MESSAGES(ViewHost)
                              int /* permission_result */)
 
   // Sent if the worker object has sent a ViewHostMsg_CreateDedicatedWorker
-  // message and not received a ViewMsg_DedicatedWorkerCreated reply, but in the
+  // message and not received a ViewMsg_WorkerCreated reply, but in the
   // mean time it's destroyed.  This tells the browser to not create the queued
   // worker.
   IPC_MESSAGE_CONTROL1(ViewHostMsg_CancelCreateDedicatedWorker,
diff --git a/chrome/common/worker_messages_internal.h b/chrome/common/worker_messages_internal.h
index 9b1cac2..6ed4d09 100644
--- a/chrome/common/worker_messages_internal.h
+++ b/chrome/common/worker_messages_internal.h
@@ -94,6 +94,10 @@ IPC_BEGIN_MESSAGES(Worker)
                       std::vector<int>  /* sent_message_port_ids */,
                       std::vector<int>  /* new_routing_ids */)
 
+  IPC_MESSAGE_ROUTED2(WorkerMsg_Connect,
+                      int /* sent_message_port_id */,
+                      int /* routing_id */)
+
   IPC_MESSAGE_ROUTED0(WorkerMsg_WorkerObjectDestroyed)
 IPC_END_MESSAGES(Worker)
 
diff --git a/chrome/renderer/renderer_webkitclient_impl.cc b/chrome/renderer/renderer_webkitclient_impl.cc
index 8203bb5..52d4a24 100644
--- a/chrome/renderer/renderer_webkitclient_impl.cc
+++ b/chrome/renderer/renderer_webkitclient_impl.cc
@@ -352,6 +352,11 @@ long long RendererWebKitClientImpl::databaseGetFileSize(
       message_id, 0LL);
 }
 
+WebKit::WebSharedWorkerRepository*
+RendererWebKitClientImpl::sharedWorkerRepository() {
+    return &shared_worker_repository_;
+}
+
 //------------------------------------------------------------------------------
 
 WebKit::WebString RendererWebKitClientImpl::signedPublicKeyAndChallengeString(
diff --git a/chrome/renderer/renderer_webkitclient_impl.h b/chrome/renderer/renderer_webkitclient_impl.h
index 79e56fc..28056c3 100644
--- a/chrome/renderer/renderer_webkitclient_impl.h
+++ b/chrome/renderer/renderer_webkitclient_impl.h
@@ -6,6 +6,7 @@
 #define CHROME_RENDERER_RENDERER_WEBKIT_CLIENT_IMPL_H_
 
 #include "base/platform_file.h"
+#include "chrome/renderer/websharedworkerrepository_impl.h"
 #include "webkit/glue/simple_webmimeregistry_impl.h"
 #include "webkit/glue/webclipboard_impl.h"
 #include "webkit/glue/webkitclient_impl.h"
@@ -64,6 +65,8 @@ class RendererWebKitClientImpl : public webkit_glue::WebKitClientImpl {
   virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost(
       WebKit::WebApplicationCacheHostClient*);
 
+  virtual WebKit::WebSharedWorkerRepository* sharedWorkerRepository();
+
  private:
   class MimeRegistry : public webkit_glue::SimpleWebMimeRegistryImpl {
    public:
@@ -106,6 +109,11 @@ class RendererWebKitClientImpl : public webkit_glue::WebKitClientImpl {
   // increments by 1, for every enable decrements by 1. When it reaches 0,
   // we tell the browser to enable fast termination.
   int sudden_termination_disables_;
+
+  // Implementation of the WebSharedWorkerRepository APIs (provides an interface
+  // to WorkerService on the browser thread.
+  WebSharedWorkerRepositoryImpl shared_worker_repository_;
+
 };
 
 #endif  // CHROME_RENDERER_WEBKIT_CLIENT_IMPL_H_
diff --git a/chrome/renderer/websharedworker_impl.cc b/chrome/renderer/websharedworker_impl.cc
new file mode 100644
index 0000000..f5e20ce
--- /dev/null
+++ b/chrome/renderer/websharedworker_impl.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/websharedworker_impl.h"
+
+#include "chrome/common/render_messages.h"
+#include "chrome/common/webmessageportchannel_impl.h"
+#include "chrome/common/worker_messages.h"
+#include "webkit/api/public/WebURL.h"
+
+WebSharedWorkerImpl::WebSharedWorkerImpl(const GURL& url,
+                                         const string16& name,
+                                         ChildThread* child_thread,
+                                         int route_id,
+                                         int render_view_route_id)
+    : WebWorkerBase(child_thread, route_id, render_view_route_id),
+      url_(url),
+      name_(name) {
+}
+
+bool WebSharedWorkerImpl::isStarted() {
+  return IsStarted();
+}
+
+void WebSharedWorkerImpl::startWorkerContext(
+    const WebKit::WebURL& script_url,
+    const WebKit::WebString& user_agent,
+    const WebKit::WebString& source_code) {
+  DCHECK(url_ == script_url);
+  IPC::Message* create_message = new ViewHostMsg_CreateSharedWorker(
+      url_, name_, render_view_route_id_, &route_id_);
+  CreateWorkerContext(create_message, script_url, user_agent, source_code);
+}
+
+void WebSharedWorkerImpl::connect(WebKit::WebMessagePortChannel* channel) {
+  WebMessagePortChannelImpl* webchannel =
+        static_cast<WebMessagePortChannelImpl*>(channel);
+
+  int message_port_id = webchannel->message_port_id();
+  DCHECK(message_port_id != MSG_ROUTING_NONE);
+  webchannel->QueueMessages();
+
+  Send(new WorkerMsg_Connect(route_id_, message_port_id, MSG_ROUTING_NONE));
+}
+
+void WebSharedWorkerImpl::OnMessageReceived(const IPC::Message& message) {
+  IPC_BEGIN_MESSAGE_MAP(WebSharedWorkerImpl, message)
+    IPC_MESSAGE_HANDLER(ViewMsg_WorkerCreated, OnWorkerCreated)
+  IPC_END_MESSAGE_MAP()
+}
+
+void WebSharedWorkerImpl::OnWorkerCreated() {
+  // The worker is created - now send off the CreateWorkerContext message and
+  // any other queued messages
+  SendQueuedMessages();
+}
+
diff --git a/chrome/renderer/websharedworker_impl.h b/chrome/renderer/websharedworker_impl.h
new file mode 100644
index 0000000..14d122d89
--- /dev/null
+++ b/chrome/renderer/websharedworker_impl.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_WEBSHAREDWORKER_IMPL_H_
+#define CHROME_RENDERER_WEBSHAREDWORKER_IMPL_H_
+
+#include "base/basictypes.h"
+#include "chrome/renderer/webworker_base.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/api/public/WebSharedWorker.h"
+
+class ChildThread;
+
+// Implementation of the WebSharedWorker APIs. This object is intended to only
+// live long enough to allow the caller to send a "connect" event to the worker
+// thread. Once the connect event has been sent, all future communication will
+// happen via the WebMessagePortChannel, and the WebSharedWorker instance will
+// be freed.
+class WebSharedWorkerImpl : public WebKit::WebSharedWorker,
+                            private WebWorkerBase {
+ public:
+  WebSharedWorkerImpl(const GURL& url,
+                      const string16& name,
+                      ChildThread* child_thread,
+                      int route_id,
+                      int render_view_route_id);
+
+  // Implementations of WebSharedWorker APIs
+  virtual bool isStarted();
+  virtual void connect(WebKit::WebMessagePortChannel* channel);
+  virtual void startWorkerContext(const WebKit::WebURL& script_url,
+                                  const WebKit::WebString& user_agent,
+                                  const WebKit::WebString& source_code);
+
+  // IPC::Channel::Listener implementation.
+  void OnMessageReceived(const IPC::Message& message);
+
+ private:
+  void OnWorkerCreated();
+
+  // The name and URL that uniquely identify this worker.
+  GURL url_;
+  string16 name_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebSharedWorkerImpl);
+};
+
+#endif  // CHROME_RENDERER_WEBSHAREDWORKER_IMPL_H_
diff --git a/chrome/renderer/websharedworkerrepository_impl.cc b/chrome/renderer/websharedworkerrepository_impl.cc
new file mode 100644
index 0000000..15aea07
--- /dev/null
+++ b/chrome/renderer/websharedworkerrepository_impl.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.  Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#include "chrome/renderer/websharedworkerrepository_impl.h"
+
+WebKit::WebSharedWorker* WebSharedWorkerRepositoryImpl::lookup(
+    const WebKit::WebURL& url,
+    const WebKit::WebString& name,
+    DocumentID document) {
+    return NULL;
+}
+
+void WebSharedWorkerRepositoryImpl::documentDetached(
+    DocumentID document) {
+    // TODO(atwilson): Update this to call to WorkerService to shutdown any
+    // associated SharedWorkers.
+}
+
+bool WebSharedWorkerRepositoryImpl::hasSharedWorkers(
+    DocumentID document) {
+    // TODO(atwilson): Update this when we track shared worker creation.
+    return false;
+}
diff --git a/chrome/renderer/websharedworkerrepository_impl.h b/chrome/renderer/websharedworkerrepository_impl.h
new file mode 100644
index 0000000..bf6369c
--- /dev/null
+++ b/chrome/renderer/websharedworkerrepository_impl.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.  Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#ifndef CHROME_RENDERER_WEB_SHARED_WORKER_REPOSITORY_IMPL_H_
+#define CHROME_RENDERER_WEB_SHARED_WORKER_REPOSITORY_IMPL_H_
+
+#include "webkit/api/public/WebSharedWorkerRepository.h"
+
+class WebKit::WebSharedWorker;
+
+class WebSharedWorkerRepositoryImpl : public WebKit::WebSharedWorkerRepository {
+    virtual WebKit::WebSharedWorker* lookup(const WebKit::WebURL& url,
+                                            const WebKit::WebString& name,
+                                            DocumentID document);
+
+    virtual void documentDetached(DocumentID document);
+
+    virtual bool hasSharedWorkers(DocumentID document);
+};
+
+#endif  // CHROME_RENDERER_WEB_SHARED_WORKER_REPOSITORY_IMPL_H_
diff --git a/chrome/renderer/webworker_base.cc b/chrome/renderer/webworker_base.cc
new file mode 100644
index 0000000..98365cd
--- /dev/null
+++ b/chrome/renderer/webworker_base.cc
@@ -0,0 +1,102 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/webworker_base.h"
+
+#include "chrome/common/child_thread.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/webmessageportchannel_impl.h"
+#include "chrome/common/worker_messages.h"
+#include "webkit/api/public/WebURL.h"
+#include "webkit/api/public/WebWorkerClient.h"
+
+using WebKit::WebMessagePortChannel;
+using WebKit::WebMessagePortChannelArray;
+using WebKit::WebString;
+using WebKit::WebURL;
+using WebKit::WebWorkerClient;
+
+WebWorkerBase::WebWorkerBase(
+    ChildThread* child_thread,
+    int route_id,
+    int render_view_route_id)
+    : route_id_(route_id),
+      render_view_route_id_(render_view_route_id),
+      child_thread_(child_thread) {
+  if (route_id_ != MSG_ROUTING_NONE)
+    child_thread_->AddRoute(route_id_, this);
+}
+
+WebWorkerBase::~WebWorkerBase() {
+  Disconnect();
+
+  // Free up any unsent queued messages.
+  for (size_t i = 0; i < queued_messages_.size(); ++i)
+    delete queued_messages_[i];
+}
+
+void WebWorkerBase::Disconnect() {
+  if (route_id_ == MSG_ROUTING_NONE)
+    return;
+
+  // So the messages from WorkerContext (like WorkerContextDestroyed) do not
+  // come after nobody is listening. Since Worker and WorkerContext can
+  // terminate independently, already sent messages may still be in the pipe.
+  child_thread_->RemoveRoute(route_id_);
+
+  route_id_ = MSG_ROUTING_NONE;
+}
+
+void WebWorkerBase::CreateWorkerContext(IPC::Message* create_message,
+                                        const GURL& script_url,
+                                        const string16& user_agent,
+                                        const string16& source_code) {
+  DCHECK(route_id_ == MSG_ROUTING_NONE);
+  // create_message is a sync message that sets route_id_
+  child_thread_->Send(create_message);
+  if (route_id_ == MSG_ROUTING_NONE)
+    return;
+
+  child_thread_->AddRoute(route_id_, this);
+
+  // We make sure that the start message is the first, since postMessage or
+  // connect might have already been called.
+  queued_messages_.insert(queued_messages_.begin(),
+      new WorkerMsg_StartWorkerContext(
+          route_id_, script_url, user_agent, source_code));
+}
+
+bool WebWorkerBase::IsStarted() {
+  // Worker is started if we have a route ID and there are no queued messages
+  // (meaning we've sent the WorkerMsg_StartWorkerContext already).
+  return (route_id_ != MSG_ROUTING_NONE && queued_messages_.empty());
+}
+
+bool WebWorkerBase::Send(IPC::Message* message) {
+  // It's possible that messages will be sent before the worker is created, in
+  // which case route_id_ will be none.  Or the worker object can be interacted
+  // with before the browser process told us that it started, in which case we
+  // also want to queue the message.
+  if (!IsStarted()) {
+    queued_messages_.push_back(message);
+    return true;
+  }
+
+  // For now we proxy all messages to the worker process through the browser.
+  // Revisit if we find this slow.
+  // TODO(jabdelmalek): handle sync messages if we need them.
+  IPC::Message* wrapped_msg = new ViewHostMsg_ForwardToWorker(*message);
+  delete message;
+  return child_thread_->Send(wrapped_msg);
+}
+
+void WebWorkerBase::SendQueuedMessages() {
+  DCHECK(queued_messages_.size());
+  std::vector<IPC::Message*> queued_messages = queued_messages_;
+  queued_messages_.clear();
+  for (size_t i = 0; i < queued_messages.size(); ++i) {
+    queued_messages[i]->set_routing_id(route_id_);
+    Send(queued_messages[i]);
+  }
+}
diff --git a/chrome/renderer/webworker_base.h b/chrome/renderer/webworker_base.h
new file mode 100644
index 0000000..c7c6c62
--- /dev/null
+++ b/chrome/renderer/webworker_base.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_WEBWORKER_BASE_H_
+#define CHROME_RENDERER_WEBWORKER_BASE_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "ipc/ipc_channel.h"
+
+class ChildThread;
+class GURL;
+
+// WebWorkerBase is the common base class used by both WebWorkerProxy and
+// WebSharedWorker. It contains logic to support starting up both dedicated
+// and shared workers, and handling message queueing while waiting for the
+// worker process to start.
+class WebWorkerBase : public IPC::Channel::Listener {
+ public:
+  WebWorkerBase(ChildThread* child_thread,
+                int route_id,
+                int render_view_route_id);
+
+  virtual ~WebWorkerBase();
+
+  // Creates and initializes a new worker context.
+  void CreateWorkerContext(IPC::Message* create_message,
+                           const GURL& script_url,
+                           const string16& user_agent,
+                           const string16& source_code);
+
+  // Returns true if the worker is running (can send messages to it).
+  bool IsStarted();
+
+  // Disconnects the worker (stops listening for incoming messages).
+  virtual void Disconnect();
+
+  // Sends a message to the worker thread (forwarded via the RenderViewHost).
+  // If WorkerStarted() has not yet been called, message is queued.
+  bool Send(IPC::Message*);
+
+  // Sends any messages currently in the queue.
+  void SendQueuedMessages();
+
+ protected:
+  // Routing id associated with this worker - used to receive messages from the
+  // worker, and also to route messages to the worker (WorkerService contains
+  // a map that maps between these renderer-side route IDs and worker-side
+  // routing ids).
+  int route_id_;
+
+  // The routing id for the RenderView that created this worker.
+  int render_view_route_id_;
+
+  ChildThread* child_thread_;
+
+ private:
+  // Stores messages that were sent before the StartWorkerContext message.
+  std::vector<IPC::Message*> queued_messages_;
+};
+
+#endif  // CHROME_RENDERER_WEBWORKER_BASE_H_
diff --git a/chrome/renderer/webworker_proxy.cc b/chrome/renderer/webworker_proxy.cc
index 3932d6e..5a24c41 100644
--- a/chrome/renderer/webworker_proxy.cc
+++ b/chrome/renderer/webworker_proxy.cc
@@ -21,51 +21,29 @@ WebWorkerProxy::WebWorkerProxy(
     WebWorkerClient* client,
     ChildThread* child_thread,
     int render_view_route_id)
-    : route_id_(MSG_ROUTING_NONE),
-      child_thread_(child_thread),
-      render_view_route_id_(render_view_route_id),
+    : WebWorkerBase(child_thread, MSG_ROUTING_NONE, render_view_route_id),
       client_(client) {
 }
 
-WebWorkerProxy::~WebWorkerProxy() {
-  Disconnect();
-
-  for (size_t i = 0; i < queued_messages_.size(); ++i)
-    delete queued_messages_[i];
-}
-
 void WebWorkerProxy::Disconnect() {
   if (route_id_ == MSG_ROUTING_NONE)
     return;
 
-  // So the messages from WorkerContext (like WorkerContextDestroyed) do not
-  // come after nobody is listening. Since Worker and WorkerContext can
-  // terminate independently, already sent messages may still be in the pipe.
-  child_thread_->RemoveRoute(route_id_);
-
   // Tell the browser to not start our queued worker.
-  if (!queued_messages_.empty())
+  if (!IsStarted())
     child_thread_->Send(new ViewHostMsg_CancelCreateDedicatedWorker(route_id_));
 
-  route_id_ = MSG_ROUTING_NONE;
+  // Call our superclass to shutdown the routing
+  WebWorkerBase::Disconnect();
 }
 
 void WebWorkerProxy::startWorkerContext(
     const WebURL& script_url,
     const WebString& user_agent,
     const WebString& source_code) {
-  child_thread_->Send(new ViewHostMsg_CreateDedicatedWorker(
-      script_url, render_view_route_id_, &route_id_));
-  if (route_id_ == MSG_ROUTING_NONE)
-    return;
-
-  child_thread_->AddRoute(route_id_, this);
-
-  // We make sure that the start message is the first, since postMessage might
-  // have already been called.
-  queued_messages_.insert(queued_messages_.begin(),
-      new WorkerMsg_StartWorkerContext(
-          route_id_, script_url, user_agent, source_code));
+  IPC::Message* create_message = new ViewHostMsg_CreateDedicatedWorker(
+      script_url, render_view_route_id_, &route_id_);
+  CreateWorkerContext(create_message, script_url, user_agent, source_code);
 }
 
 void WebWorkerProxy::terminateWorkerContext() {
@@ -100,31 +78,12 @@ void WebWorkerProxy::workerObjectDestroyed() {
 void WebWorkerProxy::clientDestroyed() {
 }
 
-bool WebWorkerProxy::Send(IPC::Message* message) {
-  // It's possible that postMessage is called before the worker is created, in
-  // which case route_id_ will be none.  Or the worker object can be interacted
-  // with before the browser process told us that it started, in which case we
-  // also want to queue the message.
-  if (route_id_ == MSG_ROUTING_NONE || !queued_messages_.empty()) {
-    queued_messages_.push_back(message);
-    return true;
-  }
-
-  // For now we proxy all messages to the worker process through the browser.
-  // Revisit if we find this slow.
-  // TODO(jabdelmalek): handle sync messages if we need them.
-  IPC::Message* wrapped_msg = new ViewHostMsg_ForwardToWorker(*message);
-  delete message;
-  return child_thread_->Send(wrapped_msg);
-}
-
 void WebWorkerProxy::OnMessageReceived(const IPC::Message& message) {
   if (!client_)
     return;
 
   IPC_BEGIN_MESSAGE_MAP(WebWorkerProxy, message)
-    IPC_MESSAGE_HANDLER(ViewMsg_DedicatedWorkerCreated,
-                        OnDedicatedWorkerCreated)
+    IPC_MESSAGE_HANDLER(ViewMsg_WorkerCreated, OnWorkerCreated)
     IPC_MESSAGE_HANDLER(WorkerMsg_PostMessage, OnPostMessage)
     IPC_MESSAGE_FORWARD(WorkerHostMsg_PostExceptionToWorkerObject,
                         client_,
@@ -143,14 +102,10 @@ void WebWorkerProxy::OnMessageReceived(const IPC::Message& message) {
   IPC_END_MESSAGE_MAP()
 }
 
-void WebWorkerProxy::OnDedicatedWorkerCreated() {
-  DCHECK(queued_messages_.size());
-  std::vector<IPC::Message*> queued_messages = queued_messages_;
-  queued_messages_.clear();
-  for (size_t i = 0; i < queued_messages.size(); ++i) {
-    queued_messages[i]->set_routing_id(route_id_);
-    Send(queued_messages[i]);
-  }
+void WebWorkerProxy::OnWorkerCreated() {
+  // The worker is created - now send off the CreateWorkerContext message and
+  // any other queued messages
+  SendQueuedMessages();
 }
 
 void WebWorkerProxy::OnPostMessage(
diff --git a/chrome/renderer/webworker_proxy.h b/chrome/renderer/webworker_proxy.h
index 8c53a67..686669a 100644
--- a/chrome/renderer/webworker_proxy.h
+++ b/chrome/renderer/webworker_proxy.h
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "chrome/renderer/webworker_base.h"
 #include "ipc/ipc_channel.h"
 #include "webkit/api/public/WebWorker.h"
 
@@ -21,13 +22,11 @@ struct WorkerHostMsg_PostConsoleMessageToWorkerObject_Params;
 // dispatched in the worker process by WebWorkerClientProxy.  It also receives
 // IPC messages from WebWorkerClientProxy which it converts to function calls to
 // WebWorkerClient.
-class WebWorkerProxy : public WebKit::WebWorker,
-                       public IPC::Channel::Listener {
+class WebWorkerProxy : public WebKit::WebWorker, private WebWorkerBase {
  public:
   WebWorkerProxy(WebKit::WebWorkerClient* client,
                  ChildThread* child_thread,
                  int render_view_route_id);
-  virtual ~WebWorkerProxy();
 
   // WebWorker implementation.
   virtual void startWorkerContext(const WebKit::WebURL& script_url,
@@ -44,32 +43,20 @@ class WebWorkerProxy : public WebKit::WebWorker,
   void OnMessageReceived(const IPC::Message& message);
 
  private:
-  bool Send(IPC::Message* message);
+  virtual void Disconnect();
 
-  void OnDedicatedWorkerCreated();
+  void OnWorkerCreated();
   void OnPostMessage(const string16& message,
                      const std::vector<int>& sent_message_port_ids,
                      const std::vector<int>& new_routing_ids);
   void OnPostConsoleMessageToWorkerObject(
       const WorkerHostMsg_PostConsoleMessageToWorkerObject_Params& params);
 
-  void Disconnect();
-
-  // The routing id used to reach WebWorkerClientProxy in the worker process.
-  int route_id_;
-
-  ChildThread* child_thread_;
-
-  // The routing id for the RenderView that created this worker.
-  int render_view_route_id_;
 
   // Used to communicate to the WebCore::Worker object in response to IPC
   // messages.
   WebKit::WebWorkerClient* client_;
 
-  // Stores messages that were sent before the StartWorkerContext message.
-  std::vector<IPC::Message*> queued_messages_;
-
   DISALLOW_COPY_AND_ASSIGN(WebWorkerProxy);
 };
 
diff --git a/chrome/worker/worker_webkitclient_impl.cc b/chrome/worker/worker_webkitclient_impl.cc
index 2d60954..fdb20f3 100644
--- a/chrome/worker/worker_webkitclient_impl.cc
+++ b/chrome/worker/worker_webkitclient_impl.cc
@@ -74,3 +74,8 @@ WebKit::WebString WorkerWebKitClientImpl::defaultLocale() {
   NOTREACHED();
   return WebKit::WebString();
 }
+
+WebKit::WebSharedWorkerRepository*
+WorkerWebKitClientImpl::sharedWorkerRepository() {
+    return 0;
+}
diff --git a/chrome/worker/worker_webkitclient_impl.h b/chrome/worker/worker_webkitclient_impl.h
index a9ccb36..c89f0fa 100644
--- a/chrome/worker/worker_webkitclient_impl.h
+++ b/chrome/worker/worker_webkitclient_impl.h
@@ -26,6 +26,7 @@ class WorkerWebKitClientImpl : public webkit_glue::WebKitClientImpl {
   virtual void prefetchHostName(const WebKit::WebString&);
   virtual bool getFileSize(const WebKit::WebString& path, long long& result);
   virtual WebKit::WebString defaultLocale();
+  virtual WebKit::WebSharedWorkerRepository* sharedWorkerRepository();
 };
 
 #endif  // CHROME_WORKER_WORKER_WEBKIT_CLIENT_IMPL_H_
-- 
cgit v1.1