1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/renderer/websharedworker_proxy.h"
6
7#include "content/child/webmessageportchannel_impl.h"
8#include "content/common/message_router.h"
9#include "content/common/view_messages.h"
10#include "content/common/worker_messages.h"
11#include "third_party/WebKit/public/platform/WebURL.h"
12#include "third_party/WebKit/public/web/WebSharedWorkerClient.h"
13
14namespace content {
15
16WebSharedWorkerProxy::WebSharedWorkerProxy(MessageRouter* router,
17                                           unsigned long long document_id,
18                                           int route_id,
19                                           int render_frame_route_id)
20    : route_id_(route_id),
21      render_frame_route_id_(render_frame_route_id),
22      router_(router),
23      document_id_(document_id),
24      pending_route_id_(route_id),
25      connect_listener_(NULL),
26      created_(false) {
27  router_->AddRoute(route_id_, this);
28}
29
30WebSharedWorkerProxy::~WebSharedWorkerProxy() {
31  Disconnect();
32
33  // Free up any unsent queued messages.
34  for (size_t i = 0; i < queued_messages_.size(); ++i)
35    delete queued_messages_[i];
36}
37
38void WebSharedWorkerProxy::Disconnect() {
39  if (route_id_ == MSG_ROUTING_NONE)
40    return;
41
42  // So the messages from WorkerContext (like WorkerContextDestroyed) do not
43  // come after nobody is listening. Since Worker and WorkerContext can
44  // terminate independently, already sent messages may still be in the pipe.
45  router_->RemoveRoute(route_id_);
46
47  route_id_ = MSG_ROUTING_NONE;
48}
49
50bool WebSharedWorkerProxy::Send(IPC::Message* message) {
51  // It's possible that messages will be sent before the worker is created, in
52  // which case route_id_ will be none.  Or the worker object can be interacted
53  // with before the browser process told us that it started, in which case we
54  // also want to queue the message.
55  if (!created_) {
56    queued_messages_.push_back(message);
57    return true;
58  }
59
60  // For now we proxy all messages to the worker process through the browser.
61  // Revisit if we find this slow.
62  // TODO(jabdelmalek): handle sync messages if we need them.
63  IPC::Message* wrapped_msg = new ViewHostMsg_ForwardToWorker(*message);
64  delete message;
65  return router_->Send(wrapped_msg);
66}
67
68void WebSharedWorkerProxy::SendQueuedMessages() {
69  DCHECK(queued_messages_.size());
70  std::vector<IPC::Message*> queued_messages = queued_messages_;
71  queued_messages_.clear();
72  for (size_t i = 0; i < queued_messages.size(); ++i) {
73    queued_messages[i]->set_routing_id(route_id_);
74    Send(queued_messages[i]);
75  }
76}
77
78void WebSharedWorkerProxy::connect(blink::WebMessagePortChannel* channel,
79                                   ConnectListener* listener) {
80  WebMessagePortChannelImpl* webchannel =
81        static_cast<WebMessagePortChannelImpl*>(channel);
82
83  int message_port_id = webchannel->message_port_id();
84  DCHECK(message_port_id != MSG_ROUTING_NONE);
85  webchannel->QueueMessages();
86
87  Send(new WorkerMsg_Connect(route_id_, message_port_id, MSG_ROUTING_NONE));
88  connect_listener_ = listener;
89}
90
91bool WebSharedWorkerProxy::OnMessageReceived(const IPC::Message& message) {
92  bool handled = true;
93  IPC_BEGIN_MESSAGE_MAP(WebSharedWorkerProxy, message)
94    IPC_MESSAGE_HANDLER(ViewMsg_WorkerCreated, OnWorkerCreated)
95    IPC_MESSAGE_HANDLER(ViewMsg_WorkerScriptLoadFailed,
96                        OnWorkerScriptLoadFailed)
97    IPC_MESSAGE_HANDLER(ViewMsg_WorkerConnected,
98                        OnWorkerConnected)
99    IPC_MESSAGE_UNHANDLED(handled = false)
100  IPC_END_MESSAGE_MAP()
101  return handled;
102}
103
104void WebSharedWorkerProxy::OnWorkerCreated() {
105  created_ = true;
106  // The worker is created - now send off the WorkerMsg_Connect message and
107  // any other queued messages
108  SendQueuedMessages();
109}
110
111void WebSharedWorkerProxy::OnWorkerScriptLoadFailed() {
112  if (connect_listener_) {
113    // This can result in this object being freed.
114    connect_listener_->scriptLoadFailed();
115  }
116}
117
118void WebSharedWorkerProxy::OnWorkerConnected() {
119  if (connect_listener_) {
120    // This can result in this object being freed.
121    connect_listener_->connected();
122  }
123}
124
125}  // namespace content
126