1 /* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "WebWorkerBase.h" 33 34 #include "GenericWorkerTask.h" 35 #include "MessagePortChannel.h" 36 #include "PlatformMessagePortChannel.h" 37 38 #include "WebDataSourceImpl.h" 39 #include "WebFrameClient.h" 40 #include "WebFrameImpl.h" 41 #include "WebMessagePortChannel.h" 42 #include "WebView.h" 43 #include "WebWorkerClient.h" 44 45 #include "WorkerThread.h" 46 #include <wtf/MainThread.h> 47 48 using namespace WebCore; 49 50 namespace WebKit { 51 52 #if ENABLE(WORKERS) 53 54 // Dummy WebViewDelegate - we only need it in Worker process to load a 55 // 'shadow page' which will initialize WebCore loader. 56 class WorkerWebFrameClient : public WebFrameClient { 57 public: 58 // Tell the loader to load the data into the 'shadow page' synchronously, 59 // so we can grab the resulting Document right after load. 60 virtual void didCreateDataSource(WebFrame* frame, WebDataSource* ds) 61 { 62 static_cast<WebDataSourceImpl*>(ds)->setDeferMainResourceDataLoad(false); 63 } 64 65 // Lazy allocate and leak this instance. 66 static WorkerWebFrameClient* sharedInstance() 67 { 68 static WorkerWebFrameClient client; 69 return &client; 70 } 71 72 private: 73 WorkerWebFrameClient() 74 { 75 } 76 }; 77 78 // This function is called on the main thread to force to initialize some static 79 // values used in WebKit before any worker thread is started. This is because in 80 // our worker processs, we do not run any WebKit code in main thread and thus 81 // when multiple workers try to start at the same time, we might hit crash due 82 // to contention for initializing static values. 83 static void initializeWebKitStaticValues() 84 { 85 static bool initialized = false; 86 if (!initialized) { 87 initialized = true; 88 // Note that we have to pass a URL with valid protocol in order to follow 89 // the path to do static value initializations. 90 RefPtr<SecurityOrigin> origin = 91 SecurityOrigin::create(KURL(ParsedURLString, "http://localhost")); 92 origin.release(); 93 } 94 } 95 96 WebWorkerBase::WebWorkerBase() 97 : m_webView(0) 98 , m_askedToTerminate(false) 99 { 100 initializeWebKitStaticValues(); 101 } 102 103 WebWorkerBase::~WebWorkerBase() 104 { 105 ASSERT(m_webView); 106 m_webView->close(); 107 } 108 109 void WebWorkerBase::stopWorkerThread() 110 { 111 if (m_askedToTerminate) 112 return; 113 m_askedToTerminate = true; 114 if (m_workerThread) 115 m_workerThread->stop(); 116 } 117 118 void WebWorkerBase::initializeLoader(const WebURL& url) 119 { 120 // Create 'shadow page'. This page is never displayed, it is used to proxy the 121 // loading requests from the worker context to the rest of WebKit and Chromium 122 // infrastructure. 123 ASSERT(!m_webView); 124 m_webView = WebView::create(0); 125 m_webView->initializeMainFrame(WorkerWebFrameClient::sharedInstance()); 126 127 WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame()); 128 129 // Construct substitute data source for the 'shadow page'. We only need it 130 // to have same origin as the worker so the loading checks work correctly. 131 CString content(""); 132 int len = static_cast<int>(content.length()); 133 RefPtr<SharedBuffer> buf(SharedBuffer::create(content.data(), len)); 134 SubstituteData substData(buf, String("text/html"), String("UTF-8"), KURL()); 135 webFrame->frame()->loader()->load(ResourceRequest(url), substData, false); 136 137 // This document will be used as 'loading context' for the worker. 138 m_loadingDocument = webFrame->frame()->document(); 139 } 140 141 void WebWorkerBase::dispatchTaskToMainThread(PassOwnPtr<ScriptExecutionContext::Task> task) 142 { 143 return callOnMainThread(invokeTaskMethod, task.release()); 144 } 145 146 void WebWorkerBase::invokeTaskMethod(void* param) 147 { 148 ScriptExecutionContext::Task* task = 149 static_cast<ScriptExecutionContext::Task*>(param); 150 task->performTask(0); 151 delete task; 152 } 153 154 // WorkerObjectProxy ----------------------------------------------------------- 155 156 void WebWorkerBase::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue> message, 157 PassOwnPtr<MessagePortChannelArray> channels) 158 { 159 dispatchTaskToMainThread(createCallbackTask(&postMessageTask, this, 160 message->toWireString(), channels)); 161 } 162 163 void WebWorkerBase::postMessageTask(ScriptExecutionContext* context, 164 WebWorkerBase* thisPtr, 165 String message, 166 PassOwnPtr<MessagePortChannelArray> channels) 167 { 168 if (!thisPtr->client()) 169 return; 170 171 WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0); 172 for (size_t i = 0; i < webChannels.size(); ++i) { 173 webChannels[i] = (*channels)[i]->channel()->webChannelRelease(); 174 webChannels[i]->setClient(0); 175 } 176 177 thisPtr->client()->postMessageToWorkerObject(message, webChannels); 178 } 179 180 void WebWorkerBase::postExceptionToWorkerObject(const String& errorMessage, 181 int lineNumber, 182 const String& sourceURL) 183 { 184 dispatchTaskToMainThread(createCallbackTask(&postExceptionTask, this, 185 errorMessage, lineNumber, 186 sourceURL)); 187 } 188 189 void WebWorkerBase::postExceptionTask(ScriptExecutionContext* context, 190 WebWorkerBase* thisPtr, 191 const String& errorMessage, 192 int lineNumber, const String& sourceURL) 193 { 194 if (!thisPtr->commonClient()) 195 return; 196 197 thisPtr->commonClient()->postExceptionToWorkerObject(errorMessage, 198 lineNumber, 199 sourceURL); 200 } 201 202 void WebWorkerBase::postConsoleMessageToWorkerObject(MessageDestination destination, 203 MessageSource source, 204 MessageType type, 205 MessageLevel level, 206 const String& message, 207 int lineNumber, 208 const String& sourceURL) 209 { 210 dispatchTaskToMainThread(createCallbackTask(&postConsoleMessageTask, this, 211 static_cast<int>(destination), 212 static_cast<int>(source), 213 static_cast<int>(type), 214 static_cast<int>(level), 215 message, lineNumber, sourceURL)); 216 } 217 218 void WebWorkerBase::postConsoleMessageTask(ScriptExecutionContext* context, 219 WebWorkerBase* thisPtr, 220 int destination, int source, 221 int type, int level, 222 const String& message, 223 int lineNumber, 224 const String& sourceURL) 225 { 226 if (!thisPtr->commonClient()) 227 return; 228 thisPtr->commonClient()->postConsoleMessageToWorkerObject(destination, source, 229 type, level, message, 230 lineNumber, sourceURL); 231 } 232 233 void WebWorkerBase::confirmMessageFromWorkerObject(bool hasPendingActivity) 234 { 235 dispatchTaskToMainThread(createCallbackTask(&confirmMessageTask, this, 236 hasPendingActivity)); 237 } 238 239 void WebWorkerBase::confirmMessageTask(ScriptExecutionContext* context, 240 WebWorkerBase* thisPtr, 241 bool hasPendingActivity) 242 { 243 if (!thisPtr->client()) 244 return; 245 thisPtr->client()->confirmMessageFromWorkerObject(hasPendingActivity); 246 } 247 248 void WebWorkerBase::reportPendingActivity(bool hasPendingActivity) 249 { 250 dispatchTaskToMainThread(createCallbackTask(&reportPendingActivityTask, 251 this, hasPendingActivity)); 252 } 253 254 void WebWorkerBase::reportPendingActivityTask(ScriptExecutionContext* context, 255 WebWorkerBase* thisPtr, 256 bool hasPendingActivity) 257 { 258 if (!thisPtr->client()) 259 return; 260 thisPtr->client()->reportPendingActivity(hasPendingActivity); 261 } 262 263 void WebWorkerBase::workerContextClosed() 264 { 265 dispatchTaskToMainThread(createCallbackTask(&workerContextClosedTask, 266 this)); 267 } 268 269 void WebWorkerBase::workerContextClosedTask(ScriptExecutionContext* context, 270 WebWorkerBase* thisPtr) 271 { 272 if (thisPtr->commonClient()) 273 thisPtr->commonClient()->workerContextClosed(); 274 275 thisPtr->stopWorkerThread(); 276 } 277 278 void WebWorkerBase::workerContextDestroyed() 279 { 280 dispatchTaskToMainThread(createCallbackTask(&workerContextDestroyedTask, 281 this)); 282 } 283 284 void WebWorkerBase::workerContextDestroyedTask(ScriptExecutionContext* context, 285 WebWorkerBase* thisPtr) 286 { 287 if (thisPtr->commonClient()) 288 thisPtr->commonClient()->workerContextDestroyed(); 289 // The lifetime of this proxy is controlled by the worker context. 290 delete thisPtr; 291 } 292 293 // WorkerLoaderProxy ----------------------------------------------------------- 294 295 void WebWorkerBase::postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task> task) 296 { 297 ASSERT(m_loadingDocument->isDocument()); 298 m_loadingDocument->postTask(task); 299 } 300 301 void WebWorkerBase::postTaskForModeToWorkerContext( 302 PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode) 303 { 304 m_workerThread->runLoop().postTaskForMode(task, mode); 305 } 306 307 #endif // ENABLE(WORKERS) 308 309 } // namespace WebKit 310