1 /* 2 * Copyright (C) 2010 Apple 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 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "InjectedBundle.h" 28 29 #include "Arguments.h" 30 #include "ImmutableArray.h" 31 #include "InjectedBundleMessageKinds.h" 32 #include "InjectedBundleScriptWorld.h" 33 #include "InjectedBundleUserMessageCoders.h" 34 #include "WKAPICast.h" 35 #include "WKBundleAPICast.h" 36 #include "WebContextMessageKinds.h" 37 #include "WebCoreArgumentCoders.h" 38 #include "WebDatabaseManager.h" 39 #include "WebFrame.h" 40 #include "WebPage.h" 41 #include "WebPreferencesStore.h" 42 #include "WebProcess.h" 43 #include <JavaScriptCore/APICast.h> 44 #include <JavaScriptCore/JSLock.h> 45 #include <WebCore/Frame.h> 46 #include <WebCore/FrameView.h> 47 #include <WebCore/GCController.h> 48 #include <WebCore/JSDOMWindow.h> 49 #include <WebCore/Page.h> 50 #include <WebCore/PageGroup.h> 51 #include <WebCore/PrintContext.h> 52 #include <WebCore/Settings.h> 53 #include <wtf/OwnArrayPtr.h> 54 #include <wtf/PassOwnArrayPtr.h> 55 56 using namespace WebCore; 57 using namespace JSC; 58 59 namespace WebKit { 60 61 InjectedBundle::InjectedBundle(const String& path) 62 : m_path(path) 63 , m_platformBundle(0) 64 { 65 initializeClient(0); 66 } 67 68 InjectedBundle::~InjectedBundle() 69 { 70 } 71 72 void InjectedBundle::initializeClient(WKBundleClient* client) 73 { 74 m_client.initialize(client); 75 } 76 77 void InjectedBundle::postMessage(const String& messageName, APIObject* messageBody) 78 { 79 WebProcess::shared().connection()->deprecatedSend(WebContextLegacyMessage::PostMessage, 0, CoreIPC::In(messageName, InjectedBundleUserMessageEncoder(messageBody))); 80 } 81 82 void InjectedBundle::postSynchronousMessage(const String& messageName, APIObject* messageBody, RefPtr<APIObject>& returnData) 83 { 84 RefPtr<APIObject> returnDataTmp; 85 InjectedBundleUserMessageDecoder messageDecoder(returnDataTmp); 86 87 bool succeeded = WebProcess::shared().connection()->deprecatedSendSync(WebContextLegacyMessage::PostSynchronousMessage, 0, CoreIPC::In(messageName, InjectedBundleUserMessageEncoder(messageBody)), CoreIPC::Out(messageDecoder)); 88 89 if (!succeeded) 90 return; 91 92 returnData = returnDataTmp; 93 } 94 95 void InjectedBundle::setShouldTrackVisitedLinks(bool shouldTrackVisitedLinks) 96 { 97 PageGroup::setShouldTrackVisitedLinks(shouldTrackVisitedLinks); 98 } 99 100 void InjectedBundle::removeAllVisitedLinks() 101 { 102 PageGroup::removeAllVisitedLinks(); 103 } 104 105 void InjectedBundle::overrideXSSAuditorEnabledForTestRunner(WebPageGroupProxy* pageGroup, bool enabled) 106 { 107 // Override the preference for all future pages. 108 WebPreferencesStore::overrideXSSAuditorEnabledForTestRunner(enabled); 109 110 // Change the setting for existing ones. 111 const HashSet<Page*>& pages = PageGroup::pageGroup(pageGroup->identifier())->pages(); 112 for (HashSet<Page*>::iterator iter = pages.begin(); iter != pages.end(); ++iter) 113 (*iter)->settings()->setXSSAuditorEnabled(enabled); 114 } 115 116 void InjectedBundle::overrideAllowUniversalAccessFromFileURLsForTestRunner(WebPageGroupProxy* pageGroup, bool enabled) 117 { 118 // Override the preference for all future pages. 119 WebPreferencesStore::overrideAllowUniversalAccessFromFileURLsForTestRunner(enabled); 120 121 // Change the setting for existing ones. 122 const HashSet<Page*>& pages = PageGroup::pageGroup(pageGroup->identifier())->pages(); 123 for (HashSet<Page*>::iterator iter = pages.begin(); iter != pages.end(); ++iter) 124 (*iter)->settings()->setAllowUniversalAccessFromFileURLs(enabled); 125 } 126 127 void InjectedBundle::setAllowFileAccessFromFileURLs(WebPageGroupProxy* pageGroup, bool enabled) 128 { 129 // Override the preference for all future pages. 130 WebPreferencesStore::overrideAllowFileAccessFromFileURLsForTestRunner(enabled); 131 132 // Change the setting for existing ones. 133 const HashSet<Page*>& pages = PageGroup::pageGroup(pageGroup->identifier())->pages(); 134 for (HashSet<Page*>::iterator iter = pages.begin(); iter != pages.end(); ++iter) 135 (*iter)->settings()->setAllowFileAccessFromFileURLs(enabled); 136 } 137 138 void InjectedBundle::clearAllDatabases() 139 { 140 WebDatabaseManager::shared().deleteAllDatabases(); 141 } 142 143 void InjectedBundle::setDatabaseQuota(uint64_t quota) 144 { 145 WebDatabaseManager::shared().setQuotaForOrigin("file:///", quota); 146 } 147 148 int InjectedBundle::numberOfPages(WebFrame* frame, double pageWidthInPixels, double pageHeightInPixels) 149 { 150 Frame* coreFrame = frame ? frame->coreFrame() : 0; 151 if (!coreFrame) 152 return -1; 153 if (!pageWidthInPixels) 154 pageWidthInPixels = coreFrame->view()->width(); 155 if (!pageHeightInPixels) 156 pageHeightInPixels = coreFrame->view()->height(); 157 158 return PrintContext::numberOfPages(coreFrame, FloatSize(pageWidthInPixels, pageHeightInPixels)); 159 } 160 161 int InjectedBundle::pageNumberForElementById(WebFrame* frame, const String& id, double pageWidthInPixels, double pageHeightInPixels) 162 { 163 Frame* coreFrame = frame ? frame->coreFrame() : 0; 164 if (!coreFrame) 165 return -1; 166 167 Element* element = coreFrame->document()->getElementById(AtomicString(id)); 168 if (!element) 169 return -1; 170 171 if (!pageWidthInPixels) 172 pageWidthInPixels = coreFrame->view()->width(); 173 if (!pageHeightInPixels) 174 pageHeightInPixels = coreFrame->view()->height(); 175 176 return PrintContext::pageNumberForElement(element, FloatSize(pageWidthInPixels, pageHeightInPixels)); 177 } 178 179 String InjectedBundle::pageSizeAndMarginsInPixels(WebFrame* frame, int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) 180 { 181 Frame* coreFrame = frame ? frame->coreFrame() : 0; 182 if (!coreFrame) 183 return String(); 184 185 return PrintContext::pageSizeAndMarginsInPixels(coreFrame, pageIndex, width, height, marginTop, marginRight, marginBottom, marginLeft); 186 } 187 188 bool InjectedBundle::isPageBoxVisible(WebFrame* frame, int pageIndex) 189 { 190 Frame* coreFrame = frame ? frame->coreFrame() : 0; 191 if (!coreFrame) 192 return false; 193 194 return PrintContext::isPageBoxVisible(coreFrame, pageIndex); 195 } 196 197 static PassOwnPtr<Vector<String> > toStringVector(ImmutableArray* patterns) 198 { 199 if (!patterns) 200 return 0; 201 202 size_t size = patterns->size(); 203 if (!size) 204 return 0; 205 206 Vector<String>* patternsVector = new Vector<String>; 207 patternsVector->reserveInitialCapacity(size); 208 for (size_t i = 0; i < size; ++i) { 209 WebString* entry = patterns->at<WebString>(i); 210 if (entry) 211 patternsVector->uncheckedAppend(entry->string()); 212 } 213 return patternsVector; 214 } 215 216 void InjectedBundle::addUserScript(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld, const String& source, const String& url, ImmutableArray* whitelist, ImmutableArray* blacklist, WebCore::UserScriptInjectionTime injectionTime, WebCore::UserContentInjectedFrames injectedFrames) 217 { 218 // url is not from KURL::string(), i.e. it has not already been parsed by KURL, so we have to use the relative URL constructor for KURL instead of the ParsedURLStringTag version. 219 PageGroup::pageGroup(pageGroup->identifier())->addUserScriptToWorld(scriptWorld->coreWorld(), source, KURL(KURL(), url), toStringVector(whitelist), toStringVector(blacklist), injectionTime, injectedFrames); 220 } 221 222 void InjectedBundle::addUserStyleSheet(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld, const String& source, const String& url, ImmutableArray* whitelist, ImmutableArray* blacklist, WebCore::UserContentInjectedFrames injectedFrames) 223 { 224 // url is not from KURL::string(), i.e. it has not already been parsed by KURL, so we have to use the relative URL constructor for KURL instead of the ParsedURLStringTag version. 225 PageGroup::pageGroup(pageGroup->identifier())->addUserStyleSheetToWorld(scriptWorld->coreWorld(), source, KURL(KURL(), url), toStringVector(whitelist), toStringVector(blacklist), injectedFrames); 226 } 227 228 void InjectedBundle::removeUserScript(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld, const String& url) 229 { 230 // url is not from KURL::string(), i.e. it has not already been parsed by KURL, so we have to use the relative URL constructor for KURL instead of the ParsedURLStringTag version. 231 PageGroup::pageGroup(pageGroup->identifier())->removeUserScriptFromWorld(scriptWorld->coreWorld(), KURL(KURL(), url)); 232 } 233 234 void InjectedBundle::removeUserStyleSheet(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld, const String& url) 235 { 236 // url is not from KURL::string(), i.e. it has not already been parsed by KURL, so we have to use the relative URL constructor for KURL instead of the ParsedURLStringTag version. 237 PageGroup::pageGroup(pageGroup->identifier())->removeUserStyleSheetFromWorld(scriptWorld->coreWorld(), KURL(KURL(), url)); 238 } 239 240 void InjectedBundle::removeUserScripts(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld) 241 { 242 PageGroup::pageGroup(pageGroup->identifier())->removeUserScriptsFromWorld(scriptWorld->coreWorld()); 243 } 244 245 void InjectedBundle::removeUserStyleSheets(WebPageGroupProxy* pageGroup, InjectedBundleScriptWorld* scriptWorld) 246 { 247 PageGroup::pageGroup(pageGroup->identifier())->removeUserStyleSheetsFromWorld(scriptWorld->coreWorld()); 248 } 249 250 void InjectedBundle::removeAllUserContent(WebPageGroupProxy* pageGroup) 251 { 252 PageGroup::pageGroup(pageGroup->identifier())->removeAllUserContent(); 253 } 254 255 void InjectedBundle::garbageCollectJavaScriptObjects() 256 { 257 gcController().garbageCollectNow(); 258 } 259 260 void InjectedBundle::garbageCollectJavaScriptObjectsOnAlternateThreadForDebugging(bool waitUntilDone) 261 { 262 gcController().garbageCollectOnAlternateThreadForDebugging(waitUntilDone); 263 } 264 265 size_t InjectedBundle::javaScriptObjectsCount() 266 { 267 JSLock lock(SilenceAssertionsOnly); 268 return JSDOMWindow::commonJSGlobalData()->heap.objectCount(); 269 } 270 271 void InjectedBundle::reportException(JSContextRef context, JSValueRef exception) 272 { 273 if (!context || !exception) 274 return; 275 276 JSLock lock(JSC::SilenceAssertionsOnly); 277 JSC::ExecState* execState = toJS(context); 278 279 // Make sure the context has a DOMWindow global object, otherwise this context didn't originate from a Page. 280 if (!toJSDOMWindow(execState->lexicalGlobalObject())) 281 return; 282 283 WebCore::reportException(execState, toJS(execState, exception)); 284 } 285 286 void InjectedBundle::didCreatePage(WebPage* page) 287 { 288 m_client.didCreatePage(this, page); 289 } 290 291 void InjectedBundle::willDestroyPage(WebPage* page) 292 { 293 m_client.willDestroyPage(this, page); 294 } 295 296 void InjectedBundle::didInitializePageGroup(WebPageGroupProxy* pageGroup) 297 { 298 m_client.didInitializePageGroup(this, pageGroup); 299 } 300 301 void InjectedBundle::didReceiveMessage(const String& messageName, APIObject* messageBody) 302 { 303 m_client.didReceiveMessage(this, messageName, messageBody); 304 } 305 306 void InjectedBundle::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments) 307 { 308 switch (messageID.get<InjectedBundleMessage::Kind>()) { 309 case InjectedBundleMessage::PostMessage: { 310 String messageName; 311 RefPtr<APIObject> messageBody; 312 InjectedBundleUserMessageDecoder messageDecoder(messageBody); 313 if (!arguments->decode(CoreIPC::Out(messageName, messageDecoder))) 314 return; 315 316 didReceiveMessage(messageName, messageBody.get()); 317 return; 318 } 319 } 320 321 ASSERT_NOT_REACHED(); 322 } 323 324 } // namespace WebKit 325