| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2008, 2009 Google Inc. All rights reserved. | |
| 3 * Copyright (C) 2009 Apple Inc. All rights reserved. | |
| 4 * | |
| 5 * Redistribution and use in source and binary forms, with or without | |
| 6 * modification, are permitted provided that the following conditions are | |
| 7 * met: | |
| 8 * | |
| 9 * * Redistributions of source code must retain the above copyright | |
| 10 * notice, this list of conditions and the following disclaimer. | |
| 11 * * Redistributions in binary form must reproduce the above | |
| 12 * copyright notice, this list of conditions and the following disclaimer | |
| 13 * in the documentation and/or other materials provided with the | |
| 14 * distribution. | |
| 15 * * Neither the name of Google Inc. nor the names of its | |
| 16 * contributors may be used to endorse or promote products derived from | |
| 17 * this software without specific prior written permission. | |
| 18 * | |
| 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 30 */ | |
| 31 | |
| 32 #include "config.h" | |
| 33 #include "bindings/v8/ScriptController.h" | |
| 34 | |
| 35 #include "bindings/core/v8/V8Event.h" | |
| 36 #include "bindings/core/v8/V8HTMLElement.h" | |
| 37 #include "bindings/core/v8/V8Window.h" | |
| 38 #include "bindings/v8/BindingSecurity.h" | |
| 39 #include "bindings/v8/NPV8Object.h" | |
| 40 #include "bindings/v8/ScriptCallStackFactory.h" | |
| 41 #include "bindings/v8/ScriptSourceCode.h" | |
| 42 #include "bindings/v8/ScriptValue.h" | |
| 43 #include "bindings/v8/V8Binding.h" | |
| 44 #include "bindings/v8/V8GCController.h" | |
| 45 #include "bindings/v8/V8NPObject.h" | |
| 46 #include "bindings/v8/V8PerContextData.h" | |
| 47 #include "bindings/v8/V8ScriptRunner.h" | |
| 48 #include "bindings/v8/V8WindowShell.h" | |
| 49 #include "bindings/v8/npruntime_impl.h" | |
| 50 #include "bindings/v8/npruntime_priv.h" | |
| 51 #include "core/dom/Document.h" | |
| 52 #include "core/dom/Node.h" | |
| 53 #include "core/dom/ScriptableDocumentParser.h" | |
| 54 #include "core/events/Event.h" | |
| 55 #include "core/events/EventListener.h" | |
| 56 #include "core/frame/LocalDOMWindow.h" | |
| 57 #include "core/frame/LocalFrame.h" | |
| 58 #include "core/frame/Settings.h" | |
| 59 #include "core/frame/UseCounter.h" | |
| 60 #include "core/frame/csp/ContentSecurityPolicy.h" | |
| 61 #include "core/html/HTMLPlugInElement.h" | |
| 62 #include "core/inspector/InspectorInstrumentation.h" | |
| 63 #include "core/inspector/InspectorTraceEvents.h" | |
| 64 #include "core/inspector/ScriptCallStack.h" | |
| 65 #include "core/loader/DocumentLoader.h" | |
| 66 #include "core/loader/FrameLoader.h" | |
| 67 #include "core/loader/FrameLoaderClient.h" | |
| 68 #include "core/plugins/PluginView.h" | |
| 69 #include "platform/NotImplemented.h" | |
| 70 #include "platform/TraceEvent.h" | |
| 71 #include "platform/UserGestureIndicator.h" | |
| 72 #include "platform/Widget.h" | |
| 73 #include "platform/weborigin/SecurityOrigin.h" | |
| 74 #include "public/platform/Platform.h" | |
| 75 #include "wtf/CurrentTime.h" | |
| 76 #include "wtf/StdLibExtras.h" | |
| 77 #include "wtf/StringExtras.h" | |
| 78 #include "wtf/text/CString.h" | |
| 79 #include "wtf/text/StringBuilder.h" | |
| 80 #include "wtf/text/TextPosition.h" | |
| 81 | |
| 82 namespace WebCore { | |
| 83 | |
| 84 bool ScriptController::canAccessFromCurrentOrigin(LocalFrame *frame) | |
| 85 { | |
| 86 if (!frame) | |
| 87 return false; | |
| 88 v8::Isolate* isolate = toIsolate(frame); | |
| 89 return !isolate->InContext() || BindingSecurity::shouldAllowAccessToFrame(is
olate, frame); | |
| 90 } | |
| 91 | |
| 92 ScriptController::ScriptController(LocalFrame* frame) | |
| 93 : m_frame(frame) | |
| 94 , m_sourceURL(0) | |
| 95 , m_isolate(v8::Isolate::GetCurrent()) | |
| 96 , m_windowShell(V8WindowShell::create(frame, DOMWrapperWorld::mainWorld(), m
_isolate)) | |
| 97 , m_windowScriptNPObject(0) | |
| 98 { | |
| 99 } | |
| 100 | |
| 101 ScriptController::~ScriptController() | |
| 102 { | |
| 103 // V8WindowShell::clearForClose() must be invoked before destruction starts. | |
| 104 ASSERT(!m_windowShell->isContextInitialized()); | |
| 105 } | |
| 106 | |
| 107 void ScriptController::clearScriptObjects() | |
| 108 { | |
| 109 PluginObjectMap::iterator it = m_pluginObjects.begin(); | |
| 110 for (; it != m_pluginObjects.end(); ++it) { | |
| 111 _NPN_UnregisterObject(it->value); | |
| 112 _NPN_ReleaseObject(it->value); | |
| 113 } | |
| 114 m_pluginObjects.clear(); | |
| 115 | |
| 116 if (m_windowScriptNPObject) { | |
| 117 // Dispose of the underlying V8 object before releasing our reference | |
| 118 // to it, so that if a plugin fails to release it properly we will | |
| 119 // only leak the NPObject wrapper, not the object, its document, or | |
| 120 // anything else they reference. | |
| 121 disposeUnderlyingV8Object(m_windowScriptNPObject, m_isolate); | |
| 122 _NPN_ReleaseObject(m_windowScriptNPObject); | |
| 123 m_windowScriptNPObject = 0; | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 void ScriptController::clearForClose() | |
| 128 { | |
| 129 double start = currentTime(); | |
| 130 m_windowShell->clearForClose(); | |
| 131 for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin(); iter != m_i
solatedWorlds.end(); ++iter) | |
| 132 iter->value->clearForClose(); | |
| 133 blink::Platform::current()->histogramCustomCounts("WebCore.ScriptController.
clearForClose", (currentTime() - start) * 1000, 0, 10000, 50); | |
| 134 } | |
| 135 | |
| 136 void ScriptController::updateSecurityOrigin(SecurityOrigin* origin) | |
| 137 { | |
| 138 m_windowShell->updateSecurityOrigin(origin); | |
| 139 } | |
| 140 | |
| 141 v8::Local<v8::Value> ScriptController::callFunction(v8::Handle<v8::Function> fun
ction, v8::Handle<v8::Value> receiver, int argc, v8::Handle<v8::Value> info[]) | |
| 142 { | |
| 143 // Keep LocalFrame (and therefore ScriptController) alive. | |
| 144 RefPtr<LocalFrame> protect(m_frame); | |
| 145 return ScriptController::callFunction(m_frame->document(), function, receive
r, argc, info, m_isolate); | |
| 146 } | |
| 147 | |
| 148 v8::Local<v8::Value> ScriptController::callFunction(ExecutionContext* context, v
8::Handle<v8::Function> function, v8::Handle<v8::Value> receiver, int argc, v8::
Handle<v8::Value> info[], v8::Isolate* isolate) | |
| 149 { | |
| 150 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "FunctionCall",
"data", devToolsTraceEventData(context, function, isolate)); | |
| 151 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "
CallStack", "stack", InspectorCallStackEvent::currentCallStack()); | |
| 152 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeli
ne migrates to tracing. | |
| 153 InspectorInstrumentationCookie cookie; | |
| 154 if (InspectorInstrumentation::timelineAgentEnabled(context)) { | |
| 155 int scriptId = 0; | |
| 156 String resourceName; | |
| 157 int lineNumber = 1; | |
| 158 GetDevToolsFunctionInfo(function, isolate, scriptId, resourceName, lineN
umber); | |
| 159 cookie = InspectorInstrumentation::willCallFunction(context, scriptId, r
esourceName, lineNumber); | |
| 160 } | |
| 161 | |
| 162 v8::Local<v8::Value> result = V8ScriptRunner::callFunction(function, context
, receiver, argc, info, isolate); | |
| 163 | |
| 164 InspectorInstrumentation::didCallFunction(cookie); | |
| 165 return result; | |
| 166 } | |
| 167 | |
| 168 v8::Local<v8::Value> ScriptController::executeScriptAndReturnValue(v8::Handle<v8
::Context> context, const ScriptSourceCode& source, AccessControlStatus corsStat
us) | |
| 169 { | |
| 170 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "EvaluateScript
", "data", InspectorEvaluateScriptEvent::data(m_frame, source.url().string(), so
urce.startLine())); | |
| 171 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "
CallStack", "stack", InspectorCallStackEvent::currentCallStack()); | |
| 172 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeli
ne migrates to tracing. | |
| 173 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvalua
teScript(m_frame, source.url().string(), source.startLine()); | |
| 174 | |
| 175 v8::Local<v8::Value> result; | |
| 176 { | |
| 177 // Isolate exceptions that occur when compiling and executing | |
| 178 // the code. These exceptions should not interfere with | |
| 179 // javascript code we might evaluate from C++ when returning | |
| 180 // from here. | |
| 181 v8::TryCatch tryCatch; | |
| 182 tryCatch.SetVerbose(true); | |
| 183 | |
| 184 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(source, m_
isolate, corsStatus); | |
| 185 | |
| 186 // Keep LocalFrame (and therefore ScriptController) alive. | |
| 187 RefPtr<LocalFrame> protect(m_frame); | |
| 188 result = V8ScriptRunner::runCompiledScript(script, m_frame->document(),
m_isolate); | |
| 189 ASSERT(!tryCatch.HasCaught() || result.IsEmpty()); | |
| 190 } | |
| 191 | |
| 192 InspectorInstrumentation::didEvaluateScript(cookie); | |
| 193 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Update
Counters", "data", InspectorUpdateCountersEvent::data()); | |
| 194 | |
| 195 return result; | |
| 196 } | |
| 197 | |
| 198 bool ScriptController::initializeMainWorld() | |
| 199 { | |
| 200 if (m_windowShell->isContextInitialized()) | |
| 201 return false; | |
| 202 return windowShell(DOMWrapperWorld::mainWorld())->isContextInitialized(); | |
| 203 } | |
| 204 | |
| 205 V8WindowShell* ScriptController::existingWindowShell(DOMWrapperWorld& world) | |
| 206 { | |
| 207 if (world.isMainWorld()) | |
| 208 return m_windowShell->isContextInitialized() ? m_windowShell.get() : 0; | |
| 209 | |
| 210 IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(world.worldId()); | |
| 211 if (iter == m_isolatedWorlds.end()) | |
| 212 return 0; | |
| 213 return iter->value->isContextInitialized() ? iter->value.get() : 0; | |
| 214 } | |
| 215 | |
| 216 V8WindowShell* ScriptController::windowShell(DOMWrapperWorld& world) | |
| 217 { | |
| 218 V8WindowShell* shell = 0; | |
| 219 if (world.isMainWorld()) | |
| 220 shell = m_windowShell.get(); | |
| 221 else { | |
| 222 IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(world.worldId())
; | |
| 223 if (iter != m_isolatedWorlds.end()) | |
| 224 shell = iter->value.get(); | |
| 225 else { | |
| 226 OwnPtr<V8WindowShell> isolatedWorldShell = V8WindowShell::create(m_f
rame, world, m_isolate); | |
| 227 shell = isolatedWorldShell.get(); | |
| 228 m_isolatedWorlds.set(world.worldId(), isolatedWorldShell.release()); | |
| 229 } | |
| 230 } | |
| 231 if (!shell->isContextInitialized() && shell->initializeIfNeeded() && world.i
sMainWorld()) | |
| 232 m_frame->loader().dispatchDidClearWindowObjectInMainWorld(); | |
| 233 return shell; | |
| 234 } | |
| 235 | |
| 236 bool ScriptController::shouldBypassMainWorldCSP() | |
| 237 { | |
| 238 v8::Handle<v8::Context> context = m_isolate->GetCurrentContext(); | |
| 239 if (context.IsEmpty() || !toDOMWindow(context)) | |
| 240 return false; | |
| 241 DOMWrapperWorld& world = DOMWrapperWorld::current(m_isolate); | |
| 242 return world.isIsolatedWorld() ? world.isolatedWorldHasContentSecurityPolicy
() : false; | |
| 243 } | |
| 244 | |
| 245 TextPosition ScriptController::eventHandlerPosition() const | |
| 246 { | |
| 247 ScriptableDocumentParser* parser = m_frame->document()->scriptableDocumentPa
rser(); | |
| 248 if (parser) | |
| 249 return parser->textPosition(); | |
| 250 return TextPosition::minimumPosition(); | |
| 251 } | |
| 252 | |
| 253 // Create a V8 object with an interceptor of NPObjectPropertyGetter. | |
| 254 void ScriptController::bindToWindowObject(LocalFrame* frame, const String& key,
NPObject* object) | |
| 255 { | |
| 256 ScriptState* scriptState = ScriptState::forMainWorld(frame); | |
| 257 if (scriptState->contextIsEmpty()) | |
| 258 return; | |
| 259 | |
| 260 ScriptState::Scope scope(scriptState); | |
| 261 v8::Handle<v8::Object> value = createV8ObjectForNPObject(object, 0, m_isolat
e); | |
| 262 | |
| 263 // Attach to the global object. | |
| 264 scriptState->context()->Global()->Set(v8String(m_isolate, key), value); | |
| 265 } | |
| 266 | |
| 267 void ScriptController::enableEval() | |
| 268 { | |
| 269 if (!m_windowShell->isContextInitialized()) | |
| 270 return; | |
| 271 v8::HandleScope handleScope(m_isolate); | |
| 272 m_windowShell->context()->AllowCodeGenerationFromStrings(true); | |
| 273 } | |
| 274 | |
| 275 void ScriptController::disableEval(const String& errorMessage) | |
| 276 { | |
| 277 if (!m_windowShell->isContextInitialized()) | |
| 278 return; | |
| 279 v8::HandleScope handleScope(m_isolate); | |
| 280 v8::Local<v8::Context> v8Context = m_windowShell->context(); | |
| 281 v8Context->AllowCodeGenerationFromStrings(false); | |
| 282 v8Context->SetErrorMessageForCodeGenerationFromStrings(v8String(m_isolate, e
rrorMessage)); | |
| 283 } | |
| 284 | |
| 285 PassRefPtr<SharedPersistent<v8::Object> > ScriptController::createPluginWrapper(
Widget* widget) | |
| 286 { | |
| 287 ASSERT(widget); | |
| 288 | |
| 289 if (!widget->isPluginView()) | |
| 290 return nullptr; | |
| 291 | |
| 292 NPObject* npObject = toPluginView(widget)->scriptableObject(); | |
| 293 if (!npObject) | |
| 294 return nullptr; | |
| 295 | |
| 296 // LocalFrame Memory Management for NPObjects | |
| 297 // ------------------------------------- | |
| 298 // NPObjects are treated differently than other objects wrapped by JS. | |
| 299 // NPObjects can be created either by the browser (e.g. the main | |
| 300 // window object) or by the plugin (the main plugin object | |
| 301 // for a HTMLEmbedElement). Further, unlike most DOM Objects, the frame | |
| 302 // is especially careful to ensure NPObjects terminate at frame teardown bec
ause | |
| 303 // if a plugin leaks a reference, it could leak its objects (or the browser'
s objects). | |
| 304 // | |
| 305 // The LocalFrame maintains a list of plugin objects (m_pluginObjects) | |
| 306 // which it can use to quickly find the wrapped embed object. | |
| 307 // | |
| 308 // Inside the NPRuntime, we've added a few methods for registering | |
| 309 // wrapped NPObjects. The purpose of the registration is because | |
| 310 // javascript garbage collection is non-deterministic, yet we need to | |
| 311 // be able to tear down the plugin objects immediately. When an object | |
| 312 // is registered, javascript can use it. When the object is destroyed, | |
| 313 // or when the object's "owning" object is destroyed, the object will | |
| 314 // be un-registered, and the javascript engine must not use it. | |
| 315 // | |
| 316 // Inside the javascript engine, the engine can keep a reference to the | |
| 317 // NPObject as part of its wrapper. However, before accessing the object | |
| 318 // it must consult the _NPN_Registry. | |
| 319 | |
| 320 v8::Local<v8::Object> wrapper = createV8ObjectForNPObject(npObject, 0, m_iso
late); | |
| 321 | |
| 322 // Track the plugin object. We've been given a reference to the object. | |
| 323 m_pluginObjects.set(widget, npObject); | |
| 324 | |
| 325 return SharedPersistent<v8::Object>::create(wrapper, m_isolate); | |
| 326 } | |
| 327 | |
| 328 void ScriptController::cleanupScriptObjectsForPlugin(Widget* nativeHandle) | |
| 329 { | |
| 330 PluginObjectMap::iterator it = m_pluginObjects.find(nativeHandle); | |
| 331 if (it == m_pluginObjects.end()) | |
| 332 return; | |
| 333 _NPN_UnregisterObject(it->value); | |
| 334 _NPN_ReleaseObject(it->value); | |
| 335 m_pluginObjects.remove(it); | |
| 336 } | |
| 337 | |
| 338 V8Extensions& ScriptController::registeredExtensions() | |
| 339 { | |
| 340 DEFINE_STATIC_LOCAL(V8Extensions, extensions, ()); | |
| 341 return extensions; | |
| 342 } | |
| 343 | |
| 344 void ScriptController::registerExtensionIfNeeded(v8::Extension* extension) | |
| 345 { | |
| 346 const V8Extensions& extensions = registeredExtensions(); | |
| 347 for (size_t i = 0; i < extensions.size(); ++i) { | |
| 348 if (extensions[i] == extension) | |
| 349 return; | |
| 350 } | |
| 351 v8::RegisterExtension(extension); | |
| 352 registeredExtensions().append(extension); | |
| 353 } | |
| 354 | |
| 355 static NPObject* createNoScriptObject() | |
| 356 { | |
| 357 notImplemented(); | |
| 358 return 0; | |
| 359 } | |
| 360 | |
| 361 static NPObject* createScriptObject(LocalFrame* frame, v8::Isolate* isolate) | |
| 362 { | |
| 363 ScriptState* scriptState = ScriptState::forMainWorld(frame); | |
| 364 if (scriptState->contextIsEmpty()) | |
| 365 return createNoScriptObject(); | |
| 366 | |
| 367 ScriptState::Scope scope(scriptState); | |
| 368 LocalDOMWindow* window = frame->domWindow(); | |
| 369 v8::Handle<v8::Value> global = toV8(window, scriptState->context()->Global()
, scriptState->isolate()); | |
| 370 ASSERT(global->IsObject()); | |
| 371 return npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(global), windo
w, isolate); | |
| 372 } | |
| 373 | |
| 374 NPObject* ScriptController::windowScriptNPObject() | |
| 375 { | |
| 376 if (m_windowScriptNPObject) | |
| 377 return m_windowScriptNPObject; | |
| 378 | |
| 379 if (canExecuteScripts(NotAboutToExecuteScript)) { | |
| 380 // JavaScript is enabled, so there is a JavaScript window object. | |
| 381 // Return an NPObject bound to the window object. | |
| 382 m_windowScriptNPObject = createScriptObject(m_frame, m_isolate); | |
| 383 _NPN_RegisterObject(m_windowScriptNPObject, 0); | |
| 384 } else { | |
| 385 // JavaScript is not enabled, so we cannot bind the NPObject to the | |
| 386 // JavaScript window object. Instead, we create an NPObject of a | |
| 387 // different class, one which is not bound to a JavaScript object. | |
| 388 m_windowScriptNPObject = createNoScriptObject(); | |
| 389 } | |
| 390 return m_windowScriptNPObject; | |
| 391 } | |
| 392 | |
| 393 NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement
* plugin) | |
| 394 { | |
| 395 // Can't create NPObjects when JavaScript is disabled. | |
| 396 if (!canExecuteScripts(NotAboutToExecuteScript)) | |
| 397 return createNoScriptObject(); | |
| 398 | |
| 399 ScriptState* scriptState = ScriptState::forMainWorld(m_frame); | |
| 400 if (scriptState->contextIsEmpty()) | |
| 401 return createNoScriptObject(); | |
| 402 | |
| 403 ScriptState::Scope scope(scriptState); | |
| 404 LocalDOMWindow* window = m_frame->domWindow(); | |
| 405 v8::Handle<v8::Value> v8plugin = toV8(plugin, scriptState->context()->Global
(), scriptState->isolate()); | |
| 406 if (!v8plugin->IsObject()) | |
| 407 return createNoScriptObject(); | |
| 408 | |
| 409 return npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(v8plugin), win
dow, scriptState->isolate()); | |
| 410 } | |
| 411 | |
| 412 void ScriptController::clearWindowShell() | |
| 413 { | |
| 414 double start = currentTime(); | |
| 415 // V8 binding expects ScriptController::clearWindowShell only be called | |
| 416 // when a frame is loading a new page. This creates a new context for the ne
w page. | |
| 417 m_windowShell->clearForNavigation(); | |
| 418 for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin(); iter != m_i
solatedWorlds.end(); ++iter) | |
| 419 iter->value->clearForNavigation(); | |
| 420 clearScriptObjects(); | |
| 421 blink::Platform::current()->histogramCustomCounts("WebCore.ScriptController.
clearWindowShell", (currentTime() - start) * 1000, 0, 10000, 50); | |
| 422 } | |
| 423 | |
| 424 void ScriptController::setCaptureCallStackForUncaughtExceptions(bool value) | |
| 425 { | |
| 426 v8::V8::SetCaptureStackTraceForUncaughtExceptions(value, ScriptCallStack::ma
xCallStackSizeToCapture, stackTraceOptions); | |
| 427 } | |
| 428 | |
| 429 void ScriptController::collectIsolatedContexts(Vector<std::pair<ScriptState*, Se
curityOrigin*> >& result) | |
| 430 { | |
| 431 for (IsolatedWorldMap::iterator it = m_isolatedWorlds.begin(); it != m_isola
tedWorlds.end(); ++it) { | |
| 432 V8WindowShell* isolatedWorldShell = it->value.get(); | |
| 433 SecurityOrigin* origin = isolatedWorldShell->world().isolatedWorldSecuri
tyOrigin(); | |
| 434 if (!origin) | |
| 435 continue; | |
| 436 if (!isolatedWorldShell->isContextInitialized()) | |
| 437 continue; | |
| 438 result.append(std::pair<ScriptState*, SecurityOrigin*>(isolatedWorldShel
l->scriptState(), origin)); | |
| 439 } | |
| 440 } | |
| 441 | |
| 442 bool ScriptController::setContextDebugId(int debugId) | |
| 443 { | |
| 444 ASSERT(debugId > 0); | |
| 445 if (!m_windowShell->isContextInitialized()) | |
| 446 return false; | |
| 447 v8::HandleScope scope(m_isolate); | |
| 448 v8::Local<v8::Context> context = m_windowShell->context(); | |
| 449 return V8PerContextDebugData::setContextDebugData(context, "page", debugId); | |
| 450 } | |
| 451 | |
| 452 int ScriptController::contextDebugId(v8::Handle<v8::Context> context) | |
| 453 { | |
| 454 return V8PerContextDebugData::contextDebugId(context); | |
| 455 } | |
| 456 | |
| 457 void ScriptController::updateDocument() | |
| 458 { | |
| 459 // For an uninitialized main window shell, do not incur the cost of context
initialization. | |
| 460 if (!m_windowShell->isGlobalInitialized()) | |
| 461 return; | |
| 462 | |
| 463 if (!initializeMainWorld()) | |
| 464 windowShell(DOMWrapperWorld::mainWorld())->updateDocument(); | |
| 465 } | |
| 466 | |
| 467 void ScriptController::namedItemAdded(HTMLDocument* doc, const AtomicString& nam
e) | |
| 468 { | |
| 469 windowShell(DOMWrapperWorld::mainWorld())->namedItemAdded(doc, name); | |
| 470 } | |
| 471 | |
| 472 void ScriptController::namedItemRemoved(HTMLDocument* doc, const AtomicString& n
ame) | |
| 473 { | |
| 474 windowShell(DOMWrapperWorld::mainWorld())->namedItemRemoved(doc, name); | |
| 475 } | |
| 476 | |
| 477 bool ScriptController::canExecuteScripts(ReasonForCallingCanExecuteScripts reaso
n) | |
| 478 { | |
| 479 v8::Handle<v8::Context> context = m_isolate->GetCurrentContext(); | |
| 480 if (!context.IsEmpty() && toDOMWindow(context) && DOMWrapperWorld::current(m
_isolate).isPrivateScriptIsolatedWorld()) { | |
| 481 return true; | |
| 482 } | |
| 483 | |
| 484 if (m_frame->document() && m_frame->document()->isSandboxed(SandboxScripts))
{ | |
| 485 // FIXME: This message should be moved off the console once a solution t
o https://bugs.webkit.org/show_bug.cgi?id=103274 exists. | |
| 486 if (reason == AboutToExecuteScript) | |
| 487 m_frame->document()->addConsoleMessage(SecurityMessageSource, ErrorM
essageLevel, "Blocked script execution in '" + m_frame->document()->url().elided
String() + "' because the document's frame is sandboxed and the 'allow-scripts'
permission is not set."); | |
| 488 return false; | |
| 489 } | |
| 490 | |
| 491 if (m_frame->document() && m_frame->document()->isViewSource()) { | |
| 492 ASSERT(m_frame->document()->securityOrigin()->isUnique()); | |
| 493 return true; | |
| 494 } | |
| 495 | |
| 496 Settings* settings = m_frame->settings(); | |
| 497 const bool allowed = m_frame->loader().client()->allowScript(settings && set
tings->scriptEnabled()); | |
| 498 if (!allowed && reason == AboutToExecuteScript) | |
| 499 m_frame->loader().client()->didNotAllowScript(); | |
| 500 return allowed; | |
| 501 } | |
| 502 | |
| 503 bool ScriptController::executeScriptIfJavaScriptURL(const KURL& url) | |
| 504 { | |
| 505 if (!protocolIsJavaScript(url)) | |
| 506 return false; | |
| 507 | |
| 508 if (!m_frame->page() | |
| 509 || !m_frame->document()->contentSecurityPolicy()->allowJavaScriptURLs(m_
frame->document()->url(), eventHandlerPosition().m_line)) | |
| 510 return true; | |
| 511 | |
| 512 // We need to hold onto the LocalFrame here because executing script can | |
| 513 // destroy the frame. | |
| 514 RefPtr<LocalFrame> protector(m_frame); | |
| 515 RefPtrWillBeRawPtr<Document> ownerDocument(m_frame->document()); | |
| 516 | |
| 517 const int javascriptSchemeLength = sizeof("javascript:") - 1; | |
| 518 | |
| 519 bool locationChangeBefore = m_frame->navigationScheduler().locationChangePen
ding(); | |
| 520 | |
| 521 String decodedURL = decodeURLEscapeSequences(url.string()); | |
| 522 v8::HandleScope handleScope(m_isolate); | |
| 523 v8::Local<v8::Value> result = evaluateScriptInMainWorld(ScriptSourceCode(dec
odedURL.substring(javascriptSchemeLength)), NotSharableCrossOrigin, DoNotExecute
ScriptWhenScriptsDisabled); | |
| 524 | |
| 525 // If executing script caused this frame to be removed from the page, we | |
| 526 // don't want to try to replace its document! | |
| 527 if (!m_frame->page()) | |
| 528 return true; | |
| 529 | |
| 530 if (result.IsEmpty() || !result->IsString()) | |
| 531 return true; | |
| 532 String scriptResult = toCoreString(v8::Handle<v8::String>::Cast(result)); | |
| 533 | |
| 534 // We're still in a frame, so there should be a DocumentLoader. | |
| 535 ASSERT(m_frame->document()->loader()); | |
| 536 if (!locationChangeBefore && m_frame->navigationScheduler().locationChangePe
nding()) | |
| 537 return true; | |
| 538 | |
| 539 // DocumentWriter::replaceDocument can cause the DocumentLoader to get deref
'ed and possible destroyed, | |
| 540 // so protect it with a RefPtr. | |
| 541 if (RefPtr<DocumentLoader> loader = m_frame->document()->loader()) { | |
| 542 UseCounter::count(*m_frame->document(), UseCounter::ReplaceDocumentViaJa
vaScriptURL); | |
| 543 loader->replaceDocument(scriptResult, ownerDocument.get()); | |
| 544 } | |
| 545 return true; | |
| 546 } | |
| 547 | |
| 548 void ScriptController::executeScriptInMainWorld(const String& script, ExecuteScr
iptPolicy policy) | |
| 549 { | |
| 550 v8::HandleScope handleScope(m_isolate); | |
| 551 evaluateScriptInMainWorld(ScriptSourceCode(script), NotSharableCrossOrigin,
policy); | |
| 552 } | |
| 553 | |
| 554 void ScriptController::executeScriptInMainWorld(const ScriptSourceCode& sourceCo
de, AccessControlStatus corsStatus) | |
| 555 { | |
| 556 v8::HandleScope handleScope(m_isolate); | |
| 557 evaluateScriptInMainWorld(sourceCode, corsStatus, DoNotExecuteScriptWhenScri
ptsDisabled); | |
| 558 } | |
| 559 | |
| 560 v8::Local<v8::Value> ScriptController::executeScriptInMainWorldAndReturnValue(co
nst ScriptSourceCode& sourceCode) | |
| 561 { | |
| 562 return evaluateScriptInMainWorld(sourceCode, NotSharableCrossOrigin, DoNotEx
ecuteScriptWhenScriptsDisabled); | |
| 563 } | |
| 564 | |
| 565 v8::Local<v8::Value> ScriptController::evaluateScriptInMainWorld(const ScriptSou
rceCode& sourceCode, AccessControlStatus corsStatus, ExecuteScriptPolicy policy) | |
| 566 { | |
| 567 if (policy == DoNotExecuteScriptWhenScriptsDisabled && !canExecuteScripts(Ab
outToExecuteScript)) | |
| 568 return v8::Local<v8::Value>(); | |
| 569 | |
| 570 String sourceURL = sourceCode.url(); | |
| 571 const String* savedSourceURL = m_sourceURL; | |
| 572 m_sourceURL = &sourceURL; | |
| 573 | |
| 574 ScriptState* scriptState = ScriptState::forMainWorld(m_frame); | |
| 575 if (scriptState->contextIsEmpty()) | |
| 576 return v8::Local<v8::Value>(); | |
| 577 | |
| 578 v8::EscapableHandleScope handleScope(scriptState->isolate()); | |
| 579 ScriptState::Scope scope(scriptState); | |
| 580 | |
| 581 RefPtr<LocalFrame> protect(m_frame); | |
| 582 if (m_frame->loader().stateMachine()->isDisplayingInitialEmptyDocument()) | |
| 583 m_frame->loader().didAccessInitialDocument(); | |
| 584 | |
| 585 OwnPtr<ScriptSourceCode> maybeProcessedSourceCode = InspectorInstrumentatio
n::preprocess(m_frame, sourceCode); | |
| 586 const ScriptSourceCode& sourceCodeToCompile = maybeProcessedSourceCode ? *ma
ybeProcessedSourceCode : sourceCode; | |
| 587 | |
| 588 v8::Local<v8::Value> object = executeScriptAndReturnValue(scriptState->conte
xt(), sourceCodeToCompile, corsStatus); | |
| 589 m_sourceURL = savedSourceURL; | |
| 590 | |
| 591 if (object.IsEmpty()) | |
| 592 return v8::Local<v8::Value>(); | |
| 593 | |
| 594 return handleScope.Escape(object); | |
| 595 } | |
| 596 | |
| 597 void ScriptController::executeScriptInIsolatedWorld(int worldID, const Vector<Sc
riptSourceCode>& sources, int extensionGroup, Vector<v8::Local<v8::Value> >* res
ults) | |
| 598 { | |
| 599 ASSERT(worldID > 0); | |
| 600 | |
| 601 RefPtr<DOMWrapperWorld> world = DOMWrapperWorld::ensureIsolatedWorld(worldID
, extensionGroup); | |
| 602 V8WindowShell* isolatedWorldShell = windowShell(*world); | |
| 603 if (!isolatedWorldShell->isContextInitialized()) | |
| 604 return; | |
| 605 | |
| 606 ScriptState* scriptState = isolatedWorldShell->scriptState(); | |
| 607 v8::EscapableHandleScope handleScope(scriptState->isolate()); | |
| 608 ScriptState::Scope scope(scriptState); | |
| 609 v8::Local<v8::Array> resultArray = v8::Array::New(m_isolate, sources.size())
; | |
| 610 | |
| 611 for (size_t i = 0; i < sources.size(); ++i) { | |
| 612 v8::Local<v8::Value> evaluationResult = executeScriptAndReturnValue(scri
ptState->context(), sources[i]); | |
| 613 if (evaluationResult.IsEmpty()) | |
| 614 evaluationResult = v8::Local<v8::Value>::New(m_isolate, v8::Undefine
d(m_isolate)); | |
| 615 resultArray->Set(i, evaluationResult); | |
| 616 } | |
| 617 | |
| 618 if (results) { | |
| 619 for (size_t i = 0; i < resultArray->Length(); ++i) | |
| 620 results->append(handleScope.Escape(resultArray->Get(i))); | |
| 621 } | |
| 622 } | |
| 623 | |
| 624 } // namespace WebCore | |
| OLD | NEW |