1/* 2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 3 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 4 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include "config.h" 22#include "ScriptController.h" 23 24#include "ContentSecurityPolicy.h" 25#include "Document.h" 26#include "DocumentLoader.h" 27#include "Frame.h" 28#include "FrameLoader.h" 29#include "FrameLoaderClient.h" 30#include "Page.h" 31#include "ScriptSourceCode.h" 32#include "ScriptValue.h" 33#include "SecurityOrigin.h" 34#include "Settings.h" 35#include "UserGestureIndicator.h" 36#include <wtf/text/TextPosition.h> 37 38namespace WebCore { 39 40bool ScriptController::canExecuteScripts(ReasonForCallingCanExecuteScripts reason) 41{ 42 if (m_frame->document() && m_frame->document()->isSandboxed(SandboxScripts)) { 43 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. 44 if (reason == AboutToExecuteScript) 45 m_frame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked script execution in '" + m_frame->document()->url().stringCenterEllipsizedToLength() + "' because the document's frame is sandboxed and the 'allow-scripts' permission is not set."); 46 return false; 47 } 48 49 if (m_frame->document() && m_frame->document()->isViewSource()) { 50 ASSERT(m_frame->document()->securityOrigin()->isUnique()); 51 return true; 52 } 53 54 Settings* settings = m_frame->settings(); 55 const bool allowed = m_frame->loader()->client()->allowScript(settings && settings->isScriptEnabled()); 56 if (!allowed && reason == AboutToExecuteScript) 57 m_frame->loader()->client()->didNotAllowScript(); 58 return allowed; 59} 60 61ScriptValue ScriptController::executeScript(const String& script, bool forceUserGesture) 62{ 63 UserGestureIndicator gestureIndicator(forceUserGesture ? DefinitelyProcessingNewUserGesture : PossiblyProcessingUserGesture); 64 return executeScript(ScriptSourceCode(script, m_frame->document()->url())); 65} 66 67ScriptValue ScriptController::executeScript(const ScriptSourceCode& sourceCode) 68{ 69 if (!canExecuteScripts(AboutToExecuteScript) || isPaused()) 70 return ScriptValue(); 71 72 RefPtr<Frame> protect(m_frame); // Script execution can destroy the frame, and thus the ScriptController. 73 74 return evaluate(sourceCode); 75} 76 77bool ScriptController::executeIfJavaScriptURL(const KURL& url, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL) 78{ 79 if (!protocolIsJavaScript(url)) 80 return false; 81 82 if (!m_frame->page() 83 || !m_frame->document()->contentSecurityPolicy()->allowJavaScriptURLs(m_frame->document()->url(), eventHandlerPosition().m_line)) 84 return true; 85 86 // We need to hold onto the Frame here because executing script can 87 // destroy the frame. 88 RefPtr<Frame> protector(m_frame); 89 RefPtr<Document> ownerDocument(m_frame->document()); 90 91 const int javascriptSchemeLength = sizeof("javascript:") - 1; 92 93 String decodedURL = decodeURLEscapeSequences(url.string()); 94 ScriptValue result = executeScript(decodedURL.substring(javascriptSchemeLength)); 95 96 // If executing script caused this frame to be removed from the page, we 97 // don't want to try to replace its document! 98 if (!m_frame->page()) 99 return true; 100 101 String scriptResult; 102 JSDOMWindowShell* shell = windowShell(mainThreadNormalWorld()); 103 JSC::ExecState* exec = shell->window()->globalExec(); 104 if (!result.getString(exec, scriptResult)) 105 return true; 106 107 // FIXME: We should always replace the document, but doing so 108 // synchronously can cause crashes: 109 // http://bugs.webkit.org/show_bug.cgi?id=16782 110 if (shouldReplaceDocumentIfJavaScriptURL == ReplaceDocumentIfJavaScriptURL) { 111 // We're still in a frame, so there should be a DocumentLoader. 112 ASSERT(m_frame->document()->loader()); 113 114 // DocumentWriter::replaceDocument can cause the DocumentLoader to get deref'ed and possible destroyed, 115 // so protect it with a RefPtr. 116 if (RefPtr<DocumentLoader> loader = m_frame->document()->loader()) 117 loader->writer()->replaceDocument(scriptResult, ownerDocument.get()); 118 } 119 return true; 120} 121 122} // namespace WebCore 123