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.
5 #include "content/renderer/websharedworker_proxy.h"
7 #include "content/child/child_thread.h"
8 #include "content/child/webmessageportchannel_impl.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"
16 WebSharedWorkerProxy::WebSharedWorkerProxy(ChildThread
* child_thread
,
17 unsigned long long document_id
,
20 int render_view_route_id
)
21 : route_id_(exists
? route_id
: MSG_ROUTING_NONE
),
22 render_view_route_id_(render_view_route_id
),
23 child_thread_(child_thread
),
24 document_id_(document_id
),
25 pending_route_id_(route_id
),
26 connect_listener_(NULL
) {
27 if (route_id_
!= MSG_ROUTING_NONE
)
28 child_thread_
->AddRoute(route_id_
, this);
31 WebSharedWorkerProxy::~WebSharedWorkerProxy() {
34 // Free up any unsent queued messages.
35 for (size_t i
= 0; i
< queued_messages_
.size(); ++i
)
36 delete queued_messages_
[i
];
39 void WebSharedWorkerProxy::Disconnect() {
40 if (route_id_
== MSG_ROUTING_NONE
)
43 // So the messages from WorkerContext (like WorkerContextDestroyed) do not
44 // come after nobody is listening. Since Worker and WorkerContext can
45 // terminate independently, already sent messages may still be in the pipe.
46 child_thread_
->RemoveRoute(route_id_
);
48 route_id_
= MSG_ROUTING_NONE
;
51 void WebSharedWorkerProxy::CreateWorkerContext(
52 const GURL
& script_url
,
55 const string16
& user_agent
,
56 const string16
& source_code
,
57 const string16
& content_security_policy
,
58 WebKit::WebContentSecurityPolicyType policy_type
,
60 int64 script_resource_appcache_id
) {
61 DCHECK(route_id_
== MSG_ROUTING_NONE
);
62 ViewHostMsg_CreateWorker_Params params
;
63 params
.url
= script_url
;
65 params
.document_id
= document_id_
;
66 params
.render_view_route_id
= render_view_route_id_
;
67 params
.route_id
= pending_route_id
;
68 params
.script_resource_appcache_id
= script_resource_appcache_id
;
69 IPC::Message
* create_message
= new ViewHostMsg_CreateWorker(
71 child_thread_
->Send(create_message
);
72 if (route_id_
== MSG_ROUTING_NONE
)
75 child_thread_
->AddRoute(route_id_
, this);
77 // We make sure that the start message is the first, since postMessage or
78 // connect might have already been called.
79 queued_messages_
.insert(queued_messages_
.begin(),
80 new WorkerMsg_StartWorkerContext(
81 route_id_
, script_url
, user_agent
, source_code
,
82 content_security_policy
, policy_type
));
85 bool WebSharedWorkerProxy::IsStarted() {
86 // Worker is started if we have a route ID and there are no queued messages
87 // (meaning we've sent the WorkerMsg_StartWorkerContext already).
88 return (route_id_
!= MSG_ROUTING_NONE
&& queued_messages_
.empty());
91 bool WebSharedWorkerProxy::Send(IPC::Message
* message
) {
92 // It's possible that messages will be sent before the worker is created, in
93 // which case route_id_ will be none. Or the worker object can be interacted
94 // with before the browser process told us that it started, in which case we
95 // also want to queue the message.
97 queued_messages_
.push_back(message
);
101 // For now we proxy all messages to the worker process through the browser.
102 // Revisit if we find this slow.
103 // TODO(jabdelmalek): handle sync messages if we need them.
104 IPC::Message
* wrapped_msg
= new ViewHostMsg_ForwardToWorker(*message
);
106 return child_thread_
->Send(wrapped_msg
);
109 void WebSharedWorkerProxy::SendQueuedMessages() {
110 DCHECK(queued_messages_
.size());
111 std::vector
<IPC::Message
*> queued_messages
= queued_messages_
;
112 queued_messages_
.clear();
113 for (size_t i
= 0; i
< queued_messages
.size(); ++i
) {
114 queued_messages
[i
]->set_routing_id(route_id_
);
115 Send(queued_messages
[i
]);
119 bool WebSharedWorkerProxy::isStarted() {
123 void WebSharedWorkerProxy::startWorkerContext(
124 const WebKit::WebURL
& script_url
,
125 const WebKit::WebString
& name
,
126 const WebKit::WebString
& user_agent
,
127 const WebKit::WebString
& source_code
,
128 const WebKit::WebString
& content_security_policy
,
129 WebKit::WebContentSecurityPolicyType policy_type
,
130 long long script_resource_appcache_id
) {
131 DCHECK(!isStarted());
133 script_url
, true, name
, user_agent
, source_code
, content_security_policy
,
134 policy_type
, pending_route_id_
, script_resource_appcache_id
);
137 void WebSharedWorkerProxy::terminateWorkerContext() {
138 // This API should only be invoked from worker context.
142 void WebSharedWorkerProxy::clientDestroyed() {
143 // This API should only be invoked from worker context.
147 void WebSharedWorkerProxy::connect(WebKit::WebMessagePortChannel
* channel
,
148 ConnectListener
* listener
) {
149 WebMessagePortChannelImpl
* webchannel
=
150 static_cast<WebMessagePortChannelImpl
*>(channel
);
152 int message_port_id
= webchannel
->message_port_id();
153 DCHECK(message_port_id
!= MSG_ROUTING_NONE
);
154 webchannel
->QueueMessages();
156 Send(new WorkerMsg_Connect(route_id_
, message_port_id
, MSG_ROUTING_NONE
));
157 if (HasQueuedMessages()) {
158 connect_listener_
= listener
;
160 listener
->connected();
161 // The listener may free this object, so do not access the object after
166 bool WebSharedWorkerProxy::OnMessageReceived(const IPC::Message
& message
) {
168 IPC_BEGIN_MESSAGE_MAP(WebSharedWorkerProxy
, message
)
169 IPC_MESSAGE_HANDLER(ViewMsg_WorkerCreated
, OnWorkerCreated
)
170 IPC_MESSAGE_UNHANDLED(handled
= false)
171 IPC_END_MESSAGE_MAP()
175 void WebSharedWorkerProxy::OnWorkerCreated() {
176 // The worker is created - now send off the CreateWorkerContext message and
177 // any other queued messages
178 SendQueuedMessages();
180 // Inform any listener that the pending connect event has been sent
181 // (this can result in this object being freed).
182 if (connect_listener_
) {
183 connect_listener_
->connected();
187 } // namespace content