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 14 namespace content { 15 16 WebSharedWorkerProxy::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 30 WebSharedWorkerProxy::~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 38 void 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 50 bool 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 68 void 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 78 void 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 91 bool 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 104 void 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 111 void WebSharedWorkerProxy::OnWorkerScriptLoadFailed() { 112 if (connect_listener_) { 113 // This can result in this object being freed. 114 connect_listener_->scriptLoadFailed(); 115 } 116 } 117 118 void 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