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 |