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 28 using WebKit::WebApplicationCacheHost; 29 using WebKit::WebFrame; 30 using WebKit::WebMessagePortChannel; 31 using WebKit::WebMessagePortChannelArray; 32 using WebKit::WebSecurityOrigin; 33 using WebKit::WebString; 34 using WebKit::WebWorker; 35 using WebKit::WebSharedWorkerClient; 36 37 namespace content { 38 39 // How long to wait for worker to finish after it's been told to terminate. 40 #define kMaxTimeForRunawayWorkerSeconds 3 41 42 WebSharedWorkerClientProxy::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 51 WebSharedWorkerClientProxy::~WebSharedWorkerClientProxy() { 52 } 53 54 void 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 72 void 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 80 void 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 97 void WebSharedWorkerClientProxy::confirmMessageFromWorkerObject( 98 bool has_pending_activity) { 99 Send(new WorkerHostMsg_ConfirmMessageFromWorkerObject( 100 route_id_, has_pending_activity)); 101 } 102 103 void WebSharedWorkerClientProxy::reportPendingActivity( 104 bool has_pending_activity) { 105 Send(new WorkerHostMsg_ReportPendingActivity( 106 route_id_, has_pending_activity)); 107 } 108 109 void WebSharedWorkerClientProxy::workerContextClosed() { 110 Send(new WorkerHostMsg_WorkerContextClosed(route_id_)); 111 } 112 113 void 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 120 WebKit::WebNotificationPresenter* 121 WebSharedWorkerClientProxy::notificationPresenter() { 122 // TODO(johnnyg): Notifications are not yet hooked up to workers. 123 // Coming soon. 124 NOTREACHED(); 125 return NULL; 126 } 127 128 WebApplicationCacheHost* 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. 142 bool 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 157 bool WebSharedWorkerClientProxy::allowFileSystem() { 158 bool result = false; 159 Send(new WorkerProcessHostMsg_AllowFileSystem( 160 route_id_, stub_->url().GetOrigin(), &result)); 161 return result; 162 } 163 164 void 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 176 bool 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 183 void 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 191 void WebSharedWorkerClientProxy::dispatchDevToolsMessage( 192 const WebString& message) { 193 if (devtools_agent_) 194 devtools_agent_->SendDevToolsMessage(message); 195 } 196 197 void WebSharedWorkerClientProxy::saveDevToolsAgentState( 198 const WebKit::WebString& state) { 199 if (devtools_agent_) 200 devtools_agent_->SaveDevToolsAgentState(state); 201 } 202 203 bool WebSharedWorkerClientProxy::Send(IPC::Message* message) { 204 return WorkerThread::current()->Send(message); 205 } 206 207 void 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