12bde8e466a4451c7319e3a072d118917957d6554Steve Block/* 22bde8e466a4451c7319e3a072d118917957d6554Steve Block * Copyright (C) 2007-2011 Google Inc. All rights reserved. 32bde8e466a4451c7319e3a072d118917957d6554Steve Block * 42bde8e466a4451c7319e3a072d118917957d6554Steve Block * Redistribution and use in source and binary forms, with or without 52bde8e466a4451c7319e3a072d118917957d6554Steve Block * modification, are permitted provided that the following conditions are 62bde8e466a4451c7319e3a072d118917957d6554Steve Block * met: 72bde8e466a4451c7319e3a072d118917957d6554Steve Block * 82bde8e466a4451c7319e3a072d118917957d6554Steve Block * * Redistributions of source code must retain the above copyright 92bde8e466a4451c7319e3a072d118917957d6554Steve Block * notice, this list of conditions and the following disclaimer. 102bde8e466a4451c7319e3a072d118917957d6554Steve Block * * Redistributions in binary form must reproduce the above 112bde8e466a4451c7319e3a072d118917957d6554Steve Block * copyright notice, this list of conditions and the following disclaimer 122bde8e466a4451c7319e3a072d118917957d6554Steve Block * in the documentation and/or other materials provided with the 132bde8e466a4451c7319e3a072d118917957d6554Steve Block * distribution. 142bde8e466a4451c7319e3a072d118917957d6554Steve Block * * Neither the name of Google Inc. nor the names of its 152bde8e466a4451c7319e3a072d118917957d6554Steve Block * contributors may be used to endorse or promote products derived from 162bde8e466a4451c7319e3a072d118917957d6554Steve Block * this software without specific prior written permission. 172bde8e466a4451c7319e3a072d118917957d6554Steve Block * 182bde8e466a4451c7319e3a072d118917957d6554Steve Block * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 192bde8e466a4451c7319e3a072d118917957d6554Steve Block * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 202bde8e466a4451c7319e3a072d118917957d6554Steve Block * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 212bde8e466a4451c7319e3a072d118917957d6554Steve Block * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 222bde8e466a4451c7319e3a072d118917957d6554Steve Block * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 232bde8e466a4451c7319e3a072d118917957d6554Steve Block * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 242bde8e466a4451c7319e3a072d118917957d6554Steve Block * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 252bde8e466a4451c7319e3a072d118917957d6554Steve Block * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 262bde8e466a4451c7319e3a072d118917957d6554Steve Block * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 272bde8e466a4451c7319e3a072d118917957d6554Steve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 282bde8e466a4451c7319e3a072d118917957d6554Steve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 292bde8e466a4451c7319e3a072d118917957d6554Steve Block */ 302bde8e466a4451c7319e3a072d118917957d6554Steve Block 312bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "config.h" 322bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "InjectedScriptManager.h" 332bde8e466a4451c7319e3a072d118917957d6554Steve Block 342bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "DOMWindow.h" 352bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "InjectedScript.h" 362bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "InjectedScriptHost.h" 372bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "ScriptValue.h" 382bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "V8Binding.h" 392bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "V8BindingState.h" 402bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "V8DOMWindow.h" 412bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "V8HiddenPropertyName.h" 422bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "V8InjectedScriptHost.h" 432bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "V8Proxy.h" 442bde8e466a4451c7319e3a072d118917957d6554Steve Block#include <wtf/RefPtr.h> 452bde8e466a4451c7319e3a072d118917957d6554Steve Block 462bde8e466a4451c7319e3a072d118917957d6554Steve Blocknamespace WebCore { 472bde8e466a4451c7319e3a072d118917957d6554Steve Block 482bde8e466a4451c7319e3a072d118917957d6554Steve Blockstatic void WeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter) 492bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 502bde8e466a4451c7319e3a072d118917957d6554Steve Block InjectedScriptHost* nativeObject = static_cast<InjectedScriptHost*>(parameter); 512bde8e466a4451c7319e3a072d118917957d6554Steve Block nativeObject->deref(); 522bde8e466a4451c7319e3a072d118917957d6554Steve Block object.Dispose(); 532bde8e466a4451c7319e3a072d118917957d6554Steve Block} 542bde8e466a4451c7319e3a072d118917957d6554Steve Block 552bde8e466a4451c7319e3a072d118917957d6554Steve Blockstatic v8::Local<v8::Object> createInjectedScriptHostV8Wrapper(InjectedScriptHost* host) 562bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 572bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Function> function = V8InjectedScriptHost::GetTemplate()->GetFunction(); 582bde8e466a4451c7319e3a072d118917957d6554Steve Block if (function.IsEmpty()) { 592bde8e466a4451c7319e3a072d118917957d6554Steve Block // Return if allocation failed. 602bde8e466a4451c7319e3a072d118917957d6554Steve Block return v8::Local<v8::Object>(); 612bde8e466a4451c7319e3a072d118917957d6554Steve Block } 622bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Object> instance = SafeAllocation::newInstance(function); 632bde8e466a4451c7319e3a072d118917957d6554Steve Block if (instance.IsEmpty()) { 642bde8e466a4451c7319e3a072d118917957d6554Steve Block // Avoid setting the wrapper if allocation failed. 652bde8e466a4451c7319e3a072d118917957d6554Steve Block return v8::Local<v8::Object>(); 662bde8e466a4451c7319e3a072d118917957d6554Steve Block } 672bde8e466a4451c7319e3a072d118917957d6554Steve Block V8DOMWrapper::setDOMWrapper(instance, &V8InjectedScriptHost::info, host); 682bde8e466a4451c7319e3a072d118917957d6554Steve Block // Create a weak reference to the v8 wrapper of InspectorBackend to deref 692bde8e466a4451c7319e3a072d118917957d6554Steve Block // InspectorBackend when the wrapper is garbage collected. 702bde8e466a4451c7319e3a072d118917957d6554Steve Block host->ref(); 712bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Persistent<v8::Object> weakHandle = v8::Persistent<v8::Object>::New(instance); 722bde8e466a4451c7319e3a072d118917957d6554Steve Block weakHandle.MakeWeak(host, &WeakReferenceCallback); 732bde8e466a4451c7319e3a072d118917957d6554Steve Block return instance; 742bde8e466a4451c7319e3a072d118917957d6554Steve Block} 752bde8e466a4451c7319e3a072d118917957d6554Steve Block 762bde8e466a4451c7319e3a072d118917957d6554Steve BlockScriptObject InjectedScriptManager::createInjectedScript(const String& scriptSource, ScriptState* inspectedScriptState, long id) 772bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 782bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::HandleScope scope; 792bde8e466a4451c7319e3a072d118917957d6554Steve Block 802bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Context> inspectedContext = inspectedScriptState->context(); 812bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Context::Scope contextScope(inspectedContext); 822bde8e466a4451c7319e3a072d118917957d6554Steve Block 832bde8e466a4451c7319e3a072d118917957d6554Steve Block // Call custom code to create InjectedScripHost wrapper specific for the context 842bde8e466a4451c7319e3a072d118917957d6554Steve Block // instead of calling toV8() that would create the 852bde8e466a4451c7319e3a072d118917957d6554Steve Block // wrapper in the current context. 862bde8e466a4451c7319e3a072d118917957d6554Steve Block // FIXME: make it possible to use generic bindings factory for InjectedScriptHost. 872bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Object> scriptHostWrapper = createInjectedScriptHostV8Wrapper(m_injectedScriptHost.get()); 882bde8e466a4451c7319e3a072d118917957d6554Steve Block if (scriptHostWrapper.IsEmpty()) 892bde8e466a4451c7319e3a072d118917957d6554Steve Block return ScriptObject(); 902bde8e466a4451c7319e3a072d118917957d6554Steve Block 912bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Object> windowGlobal = inspectedContext->Global(); 922bde8e466a4451c7319e3a072d118917957d6554Steve Block 932bde8e466a4451c7319e3a072d118917957d6554Steve Block // Inject javascript into the context. The compiled script is supposed to evaluate into 942bde8e466a4451c7319e3a072d118917957d6554Steve Block // a single anonymous function(it's anonymous to avoid cluttering the global object with 952bde8e466a4451c7319e3a072d118917957d6554Steve Block // inspector's stuff) the function is called a few lines below with InjectedScriptHost wrapper, 962bde8e466a4451c7319e3a072d118917957d6554Steve Block // injected script id and explicit reference to the inspected global object. The function is expected 972bde8e466a4451c7319e3a072d118917957d6554Steve Block // to create and configure InjectedScript instance that is going to be used by the inspector. 982bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Script> script = v8::Script::Compile(v8String(scriptSource)); 992bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Value> v = script->Run(); 1002bde8e466a4451c7319e3a072d118917957d6554Steve Block ASSERT(!v.IsEmpty()); 1012bde8e466a4451c7319e3a072d118917957d6554Steve Block ASSERT(v->IsFunction()); 1022bde8e466a4451c7319e3a072d118917957d6554Steve Block 1032bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Handle<v8::Value> args[] = { 1042bde8e466a4451c7319e3a072d118917957d6554Steve Block scriptHostWrapper, 1052bde8e466a4451c7319e3a072d118917957d6554Steve Block windowGlobal, 1062bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Number::New(id), 1072bde8e466a4451c7319e3a072d118917957d6554Steve Block }; 1082bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Value> injectedScriptValue = v8::Function::Cast(*v)->Call(windowGlobal, 3, args); 1092bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Object> injectedScript(v8::Object::Cast(*injectedScriptValue)); 1102bde8e466a4451c7319e3a072d118917957d6554Steve Block return ScriptObject(inspectedScriptState, injectedScript); 1112bde8e466a4451c7319e3a072d118917957d6554Steve Block} 1122bde8e466a4451c7319e3a072d118917957d6554Steve Block 1132bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid InjectedScriptManager::discardInjectedScript(ScriptState* inspectedScriptState) 1142bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 1152bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::HandleScope handleScope; 1162bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Context> context = inspectedScriptState->context(); 1172bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Context::Scope contextScope(context); 1182bde8e466a4451c7319e3a072d118917957d6554Steve Block 1192bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Object> global = context->Global(); 1202bde8e466a4451c7319e3a072d118917957d6554Steve Block // Skip proxy object. The proxy object will survive page navigation while we need 1212bde8e466a4451c7319e3a072d118917957d6554Steve Block // an object whose lifetime consides with that of the inspected context. 1222bde8e466a4451c7319e3a072d118917957d6554Steve Block global = v8::Local<v8::Object>::Cast(global->GetPrototype()); 1232bde8e466a4451c7319e3a072d118917957d6554Steve Block 1242bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Handle<v8::String> key = V8HiddenPropertyName::devtoolsInjectedScript(); 1252bde8e466a4451c7319e3a072d118917957d6554Steve Block global->DeleteHiddenValue(key); 1262bde8e466a4451c7319e3a072d118917957d6554Steve Block} 1272bde8e466a4451c7319e3a072d118917957d6554Steve Block 1282bde8e466a4451c7319e3a072d118917957d6554Steve BlockInjectedScript InjectedScriptManager::injectedScriptFor(ScriptState* inspectedScriptState) 1292bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 1302bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::HandleScope handleScope; 1312bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Context> context = inspectedScriptState->context(); 1322bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Context::Scope contextScope(context); 1332bde8e466a4451c7319e3a072d118917957d6554Steve Block 1342bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Object> global = context->Global(); 1352bde8e466a4451c7319e3a072d118917957d6554Steve Block // Skip proxy object. The proxy object will survive page navigation while we need 1362bde8e466a4451c7319e3a072d118917957d6554Steve Block // an object whose lifetime consides with that of the inspected context. 1372bde8e466a4451c7319e3a072d118917957d6554Steve Block global = v8::Local<v8::Object>::Cast(global->GetPrototype()); 1382bde8e466a4451c7319e3a072d118917957d6554Steve Block 1392bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Handle<v8::String> key = V8HiddenPropertyName::devtoolsInjectedScript(); 1402bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Value> val = global->GetHiddenValue(key); 1412bde8e466a4451c7319e3a072d118917957d6554Steve Block if (!val.IsEmpty() && val->IsObject()) 1422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return InjectedScript(ScriptObject(inspectedScriptState, v8::Local<v8::Object>::Cast(val)), m_inspectedStateAccessCheck); 1432bde8e466a4451c7319e3a072d118917957d6554Steve Block 1442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (!m_inspectedStateAccessCheck(inspectedScriptState)) 1452bde8e466a4451c7319e3a072d118917957d6554Steve Block return InjectedScript(); 1462bde8e466a4451c7319e3a072d118917957d6554Steve Block 1472bde8e466a4451c7319e3a072d118917957d6554Steve Block pair<long, ScriptObject> injectedScript = injectScript(injectedScriptSource(), inspectedScriptState); 1482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InjectedScript result(injectedScript.second, m_inspectedStateAccessCheck); 1492bde8e466a4451c7319e3a072d118917957d6554Steve Block m_idToInjectedScript.set(injectedScript.first, result); 1502bde8e466a4451c7319e3a072d118917957d6554Steve Block global->SetHiddenValue(key, injectedScript.second.v8Object()); 1512bde8e466a4451c7319e3a072d118917957d6554Steve Block return result; 1522bde8e466a4451c7319e3a072d118917957d6554Steve Block} 1532bde8e466a4451c7319e3a072d118917957d6554Steve Block 1542bde8e466a4451c7319e3a072d118917957d6554Steve Blockbool InjectedScriptManager::canAccessInspectedWindow(ScriptState* scriptState) 1552bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 1562bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::HandleScope handleScope; 1572bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Context> context = scriptState->context(); 1582bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Local<v8::Object> global = context->Global(); 1592bde8e466a4451c7319e3a072d118917957d6554Steve Block if (global.IsEmpty()) 1602bde8e466a4451c7319e3a072d118917957d6554Steve Block return false; 1612bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global); 1622bde8e466a4451c7319e3a072d118917957d6554Steve Block if (holder.IsEmpty()) 1632bde8e466a4451c7319e3a072d118917957d6554Steve Block return false; 1642bde8e466a4451c7319e3a072d118917957d6554Steve Block Frame* frame = V8DOMWindow::toNative(holder)->frame(); 1652bde8e466a4451c7319e3a072d118917957d6554Steve Block 1662bde8e466a4451c7319e3a072d118917957d6554Steve Block v8::Context::Scope contextScope(context); 1672bde8e466a4451c7319e3a072d118917957d6554Steve Block return V8BindingSecurity::canAccessFrame(V8BindingState::Only(), frame, false); 1682bde8e466a4451c7319e3a072d118917957d6554Steve Block} 1692bde8e466a4451c7319e3a072d118917957d6554Steve Block 1702bde8e466a4451c7319e3a072d118917957d6554Steve Block} // namespace WebCore 171