1// Copyright (c) 2012 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/worker/websharedworkerclient_proxy.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/message_loop/message_loop.h"
10#include "content/child/fileapi/file_system_dispatcher.h"
11#include "content/child/fileapi/webfilesystem_callback_adapters.h"
12#include "content/child/quota_dispatcher.h"
13#include "content/child/webmessageportchannel_impl.h"
14#include "content/common/worker_messages.h"
15#include "content/public/common/content_switches.h"
16#include "content/worker/shared_worker_devtools_agent.h"
17#include "content/worker/websharedworker_stub.h"
18#include "content/worker/worker_thread.h"
19#include "content/worker/worker_webapplicationcachehost_impl.h"
20#include "ipc/ipc_logging.h"
21#include "third_party/WebKit/public/platform/WebString.h"
22#include "third_party/WebKit/public/platform/WebURL.h"
23#include "third_party/WebKit/public/web/WebDocument.h"
24#include "third_party/WebKit/public/web/WebFileSystemCallbacks.h"
25#include "third_party/WebKit/public/web/WebFrame.h"
26#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
27
28using WebKit::WebApplicationCacheHost;
29using WebKit::WebFrame;
30using WebKit::WebMessagePortChannel;
31using WebKit::WebMessagePortChannelArray;
32using WebKit::WebSecurityOrigin;
33using WebKit::WebString;
34using WebKit::WebWorker;
35using WebKit::WebSharedWorkerClient;
36
37namespace content {
38
39// How long to wait for worker to finish after it's been told to terminate.
40#define kMaxTimeForRunawayWorkerSeconds 3
41
42WebSharedWorkerClientProxy::WebSharedWorkerClientProxy(
43    int route_id, WebSharedWorkerStub* stub)
44    : route_id_(route_id),
45      appcache_host_id_(0),
46      stub_(stub),
47      weak_factory_(this),
48      devtools_agent_(NULL) {
49}
50
51WebSharedWorkerClientProxy::~WebSharedWorkerClientProxy() {
52}
53
54void WebSharedWorkerClientProxy::postMessageToWorkerObject(
55    const WebString& message,
56    const WebMessagePortChannelArray& channels) {
57  std::vector<int> message_port_ids(channels.size());
58  std::vector<int> routing_ids(channels.size());
59  for (size_t i = 0; i < channels.size(); ++i) {
60    WebMessagePortChannelImpl* webchannel =
61        static_cast<WebMessagePortChannelImpl*>(channels[i]);
62    message_port_ids[i] = webchannel->message_port_id();
63    webchannel->QueueMessages();
64    DCHECK(message_port_ids[i] != MSG_ROUTING_NONE);
65    routing_ids[i] = MSG_ROUTING_NONE;
66  }
67
68  Send(new WorkerMsg_PostMessage(
69      route_id_, message, message_port_ids, routing_ids));
70}
71
72void WebSharedWorkerClientProxy::postExceptionToWorkerObject(
73    const WebString& error_message,
74    int line_number,
75    const WebString& source_url) {
76  Send(new WorkerHostMsg_PostExceptionToWorkerObject(
77      route_id_, error_message, line_number, source_url));
78}
79
80void WebSharedWorkerClientProxy::postConsoleMessageToWorkerObject(
81    int source,
82    int type,
83    int level,
84    const WebString& message,
85    int line_number,
86    const WebString& source_url) {
87  WorkerHostMsg_PostConsoleMessageToWorkerObject_Params params;
88  params.source_identifier = source;
89  params.message_type = type;
90  params.message_level = level;
91  params.message = message;
92  params.line_number = line_number;
93  params.source_url = source_url;
94  Send(new WorkerHostMsg_PostConsoleMessageToWorkerObject(route_id_, params));
95}
96
97void WebSharedWorkerClientProxy::confirmMessageFromWorkerObject(
98    bool has_pending_activity) {
99  Send(new WorkerHostMsg_ConfirmMessageFromWorkerObject(
100      route_id_, has_pending_activity));
101}
102
103void WebSharedWorkerClientProxy::reportPendingActivity(
104    bool has_pending_activity) {
105  Send(new WorkerHostMsg_ReportPendingActivity(
106      route_id_, has_pending_activity));
107}
108
109void WebSharedWorkerClientProxy::workerContextClosed() {
110  Send(new WorkerHostMsg_WorkerContextClosed(route_id_));
111}
112
113void WebSharedWorkerClientProxy::workerContextDestroyed() {
114  Send(new WorkerHostMsg_WorkerContextDestroyed(route_id_));
115  // Tell the stub that the worker has shutdown - frees this object.
116  if (stub_)
117    stub_->Shutdown();
118}
119
120WebKit::WebNotificationPresenter*
121WebSharedWorkerClientProxy::notificationPresenter() {
122  // TODO(johnnyg): Notifications are not yet hooked up to workers.
123  // Coming soon.
124  NOTREACHED();
125  return NULL;
126}
127
128WebApplicationCacheHost* WebSharedWorkerClientProxy::createApplicationCacheHost(
129    WebKit::WebApplicationCacheHostClient* client) {
130  WorkerWebApplicationCacheHostImpl* host =
131      new WorkerWebApplicationCacheHostImpl(stub_->appcache_init_info(),
132                                            client);
133  // Remember the id of the instance we create so we have access to that
134  // value when creating nested dedicated workers in createWorker.
135  appcache_host_id_ = host->host_id();
136  return host;
137}
138
139// TODO(abarth): Security checks should use WebDocument or WebSecurityOrigin,
140// not WebFrame as the context object because WebFrames can contain different
141// WebDocuments at different times.
142bool WebSharedWorkerClientProxy::allowDatabase(WebFrame* frame,
143                                         const WebString& name,
144                                         const WebString& display_name,
145                                         unsigned long estimated_size) {
146  WebSecurityOrigin origin = frame->document().securityOrigin();
147  if (origin.isUnique())
148    return false;
149
150  bool result = false;
151  Send(new WorkerProcessHostMsg_AllowDatabase(
152      route_id_, GURL(origin.toString().utf8()), name, display_name,
153      estimated_size, &result));
154  return result;
155}
156
157bool WebSharedWorkerClientProxy::allowFileSystem() {
158  bool result = false;
159  Send(new WorkerProcessHostMsg_AllowFileSystem(
160      route_id_, stub_->url().GetOrigin(), &result));
161  return result;
162}
163
164void WebSharedWorkerClientProxy::openFileSystem(
165    WebKit::WebFileSystemType type,
166    long long size,
167    bool create,
168    WebKit::WebFileSystemCallbacks* callbacks) {
169  ChildThread::current()->file_system_dispatcher()->OpenFileSystem(
170      stub_->url().GetOrigin(), static_cast<fileapi::FileSystemType>(type),
171      size, create,
172      base::Bind(&OpenFileSystemCallbackAdapter, callbacks),
173      base::Bind(&FileStatusCallbackAdapter, callbacks));
174}
175
176bool WebSharedWorkerClientProxy::allowIndexedDB(const WebKit::WebString& name) {
177  bool result = false;
178  Send(new WorkerProcessHostMsg_AllowIndexedDB(
179      route_id_, stub_->url().GetOrigin(), name, &result));
180  return result;
181}
182
183void WebSharedWorkerClientProxy::queryUsageAndQuota(
184    WebKit::WebStorageQuotaType type,
185    WebKit::WebStorageQuotaCallbacks* callbacks) {
186  ChildThread::current()->quota_dispatcher()->QueryStorageUsageAndQuota(
187      stub_->url().GetOrigin(), static_cast<quota::StorageType>(type),
188      QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks));
189}
190
191void WebSharedWorkerClientProxy::dispatchDevToolsMessage(
192    const WebString& message) {
193  if (devtools_agent_)
194    devtools_agent_->SendDevToolsMessage(message);
195}
196
197void WebSharedWorkerClientProxy::saveDevToolsAgentState(
198    const WebKit::WebString& state) {
199  if (devtools_agent_)
200    devtools_agent_->SaveDevToolsAgentState(state);
201}
202
203bool WebSharedWorkerClientProxy::Send(IPC::Message* message) {
204  return WorkerThread::current()->Send(message);
205}
206
207void WebSharedWorkerClientProxy::EnsureWorkerContextTerminates() {
208  // This shuts down the process cleanly from the perspective of the browser
209  // process, and avoids the crashed worker infobar from appearing to the new
210  // page. It's ok to post several of theese, because the first executed task
211  // will exit the message loop and subsequent ones won't be executed.
212  base::MessageLoop::current()->PostDelayedTask(
213      FROM_HERE,
214      base::Bind(&WebSharedWorkerClientProxy::workerContextDestroyed,
215                 weak_factory_.GetWeakPtr()),
216      base::TimeDelta::FromSeconds(kMaxTimeForRunawayWorkerSeconds));
217}
218
219}  // namespace content
220