1 /* 2 * Copyright (C) 2007-2011 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "V8InjectedScriptHost.h" 33 34 #include "V8Database.h" 35 #include "V8HTMLAllCollection.h" 36 #include "V8HTMLCollection.h" 37 #include "V8Node.h" 38 #include "V8NodeList.h" 39 #include "V8Storage.h" 40 #include "bindings/v8/BindingSecurity.h" 41 #include "bindings/v8/ScriptDebugServer.h" 42 #include "bindings/v8/ScriptValue.h" 43 #include "bindings/v8/V8AbstractEventListener.h" 44 #include "bindings/v8/V8Binding.h" 45 #include "bindings/v8/V8HiddenPropertyName.h" 46 #include "bindings/v8/V8ScriptRunner.h" 47 #include "bindings/v8/custom/V8Float32ArrayCustom.h" 48 #include "bindings/v8/custom/V8Float64ArrayCustom.h" 49 #include "bindings/v8/custom/V8Int16ArrayCustom.h" 50 #include "bindings/v8/custom/V8Int32ArrayCustom.h" 51 #include "bindings/v8/custom/V8Int8ArrayCustom.h" 52 #include "bindings/v8/custom/V8Uint16ArrayCustom.h" 53 #include "bindings/v8/custom/V8Uint32ArrayCustom.h" 54 #include "bindings/v8/custom/V8Uint8ArrayCustom.h" 55 #include "bindings/v8/custom/V8Uint8ClampedArrayCustom.h" 56 #include "core/inspector/InjectedScript.h" 57 #include "core/inspector/InjectedScriptHost.h" 58 #include "core/inspector/InspectorDOMAgent.h" 59 #include "core/platform/JSONValues.h" 60 #include "modules/webdatabase/Database.h" 61 62 namespace WebCore { 63 64 Node* InjectedScriptHost::scriptValueAsNode(ScriptValue value) 65 { 66 v8::HandleScope scope(v8::Isolate::GetCurrent()); 67 if (!value.isObject() || value.isNull()) 68 return 0; 69 return V8Node::toNative(v8::Handle<v8::Object>::Cast(value.v8Value())); 70 } 71 72 ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* state, Node* node) 73 { 74 v8::HandleScope scope; 75 v8::Local<v8::Context> context = state->context(); 76 v8::Context::Scope contextScope(context); 77 78 if (!BindingSecurity::shouldAllowAccessToNode(node)) 79 return ScriptValue(v8::Null()); 80 return ScriptValue(toV8(node, v8::Handle<v8::Object>(), context->GetIsolate())); 81 } 82 83 void V8InjectedScriptHost::inspectedObjectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 84 { 85 if (args.Length() < 1) 86 return; 87 88 if (!args[0]->IsInt32()) { 89 throwTypeError("argument has to be an integer", args.GetIsolate()); 90 return; 91 } 92 93 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 94 InjectedScriptHost::InspectableObject* object = host->inspectedObject(args[0]->ToInt32()->Value()); 95 v8SetReturnValue(args, object->get(ScriptState::current()).v8Value()); 96 } 97 98 void V8InjectedScriptHost::internalConstructorNameMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 99 { 100 if (args.Length() < 1) 101 return; 102 103 if (!args[0]->IsObject()) 104 return; 105 106 v8SetReturnValue(args, args[0]->ToObject()->GetConstructorName()); 107 } 108 109 void V8InjectedScriptHost::isHTMLAllCollectionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 110 { 111 if (args.Length() < 1) 112 return; 113 114 if (!args[0]->IsObject()) { 115 v8SetReturnValue(args, false); 116 return; 117 } 118 119 v8SetReturnValue(args, V8HTMLAllCollection::HasInstance(args[0], args.GetIsolate(), worldType(args.GetIsolate()))); 120 } 121 122 void V8InjectedScriptHost::typeMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 123 { 124 if (args.Length() < 1) 125 return; 126 127 v8::Handle<v8::Value> value = args[0]; 128 if (value->IsString()) { 129 v8SetReturnValue(args, v8::String::NewSymbol("string")); 130 return; 131 } 132 if (value->IsArray()) { 133 v8SetReturnValue(args, v8::String::NewSymbol("array")); 134 return; 135 } 136 if (value->IsBoolean()) { 137 v8SetReturnValue(args, v8::String::NewSymbol("boolean")); 138 return; 139 } 140 if (value->IsNumber()) { 141 v8SetReturnValue(args, v8::String::NewSymbol("number")); 142 return; 143 } 144 if (value->IsDate()) { 145 v8SetReturnValue(args, v8::String::NewSymbol("date")); 146 return; 147 } 148 if (value->IsRegExp()) { 149 v8SetReturnValue(args, v8::String::NewSymbol("regexp")); 150 return; 151 } 152 WrapperWorldType currentWorldType = worldType(args.GetIsolate()); 153 if (V8Node::HasInstance(value, args.GetIsolate(), currentWorldType)) { 154 v8SetReturnValue(args, v8::String::NewSymbol("node")); 155 return; 156 } 157 if (V8NodeList::HasInstance(value, args.GetIsolate(), currentWorldType)) { 158 v8SetReturnValue(args, v8::String::NewSymbol("array")); 159 return; 160 } 161 if (V8HTMLCollection::HasInstance(value, args.GetIsolate(), currentWorldType)) { 162 v8SetReturnValue(args, v8::String::NewSymbol("array")); 163 return; 164 } 165 if (V8Int8Array::HasInstance(value, args.GetIsolate(), currentWorldType) || V8Int16Array::HasInstance(value, args.GetIsolate(), currentWorldType) || V8Int32Array::HasInstance(value, args.GetIsolate(), currentWorldType)) { 166 v8SetReturnValue(args, v8::String::NewSymbol("array")); 167 return; 168 } 169 if (V8Uint8Array::HasInstance(value, args.GetIsolate(), currentWorldType) || V8Uint16Array::HasInstance(value, args.GetIsolate(), currentWorldType) || V8Uint32Array::HasInstance(value, args.GetIsolate(), currentWorldType)) { 170 v8SetReturnValue(args, v8::String::NewSymbol("array")); 171 return; 172 } 173 if (V8Float32Array::HasInstance(value, args.GetIsolate(), currentWorldType) || V8Float64Array::HasInstance(value, args.GetIsolate(), currentWorldType)) { 174 v8SetReturnValue(args, v8::String::NewSymbol("array")); 175 return; 176 } 177 if (V8Uint8ClampedArray::HasInstance(value, args.GetIsolate(), currentWorldType)) { 178 v8SetReturnValue(args, v8::String::NewSymbol("array")); 179 return; 180 } 181 } 182 183 void V8InjectedScriptHost::functionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 184 { 185 if (args.Length() < 1) 186 return; 187 188 v8::Handle<v8::Value> value = args[0]; 189 if (!value->IsFunction()) 190 return; 191 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value); 192 int lineNumber = function->GetScriptLineNumber(); 193 int columnNumber = function->GetScriptColumnNumber(); 194 195 v8::Local<v8::Object> location = v8::Object::New(); 196 location->Set(v8::String::NewSymbol("lineNumber"), v8::Integer::New(lineNumber, args.GetIsolate())); 197 location->Set(v8::String::NewSymbol("columnNumber"), v8::Integer::New(columnNumber, args.GetIsolate())); 198 location->Set(v8::String::NewSymbol("scriptId"), function->GetScriptId()->ToString()); 199 200 v8::Local<v8::Object> result = v8::Object::New(); 201 result->Set(v8::String::NewSymbol("location"), location); 202 203 v8::Handle<v8::Value> name = function->GetName(); 204 if (name->IsString() && v8::Handle<v8::String>::Cast(name)->Length()) 205 result->Set(v8::String::NewSymbol("name"), name); 206 207 v8::Handle<v8::Value> inferredName = function->GetInferredName(); 208 if (inferredName->IsString() && v8::Handle<v8::String>::Cast(inferredName)->Length()) 209 result->Set(v8::String::NewSymbol("inferredName"), inferredName); 210 211 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 212 ScriptDebugServer& debugServer = host->scriptDebugServer(); 213 v8::Handle<v8::Value> scopes = debugServer.functionScopes(function); 214 if (!scopes.IsEmpty() && scopes->IsArray()) 215 result->Set(v8::String::NewSymbol("rawScopes"), scopes); 216 217 v8SetReturnValue(args, result); 218 } 219 220 void V8InjectedScriptHost::getInternalPropertiesMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 221 { 222 if (args.Length() < 1) 223 return; 224 225 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(args[0]); 226 227 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 228 ScriptDebugServer& debugServer = host->scriptDebugServer(); 229 v8SetReturnValue(args, debugServer.getInternalProperties(object)); 230 } 231 232 static v8::Handle<v8::Array> getJSListenerFunctions(Document* document, const EventListenerInfo& listenerInfo) 233 { 234 v8::Local<v8::Array> result = v8::Array::New(); 235 size_t handlersCount = listenerInfo.eventListenerVector.size(); 236 for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) { 237 RefPtr<EventListener> listener = listenerInfo.eventListenerVector[i].listener; 238 if (listener->type() != EventListener::JSEventListenerType) { 239 ASSERT_NOT_REACHED(); 240 continue; 241 } 242 V8AbstractEventListener* v8Listener = static_cast<V8AbstractEventListener*>(listener.get()); 243 v8::Local<v8::Context> context = toV8Context(document, v8Listener->world()); 244 // Hide listeners from other contexts. 245 if (context != v8::Context::GetCurrent()) 246 continue; 247 v8::Local<v8::Object> function; 248 { 249 // getListenerObject() may cause JS in the event attribute to get compiled, potentially unsuccessfully. 250 v8::TryCatch block; 251 function = v8Listener->getListenerObject(document); 252 if (block.HasCaught()) 253 continue; 254 } 255 ASSERT(!function.IsEmpty()); 256 v8::Local<v8::Object> listenerEntry = v8::Object::New(); 257 listenerEntry->Set(v8::String::NewSymbol("listener"), function); 258 listenerEntry->Set(v8::String::NewSymbol("useCapture"), v8::Boolean::New(listenerInfo.eventListenerVector[i].useCapture)); 259 result->Set(v8::Number::New(outputIndex++), listenerEntry); 260 } 261 return result; 262 } 263 264 void V8InjectedScriptHost::getEventListenersMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 265 { 266 if (args.Length() < 1) 267 return; 268 269 v8::Local<v8::Value> value = args[0]; 270 if (!V8Node::HasInstance(value, args.GetIsolate(), worldType(args.GetIsolate()))) 271 return; 272 Node* node = V8Node::toNative(value->ToObject()); 273 if (!node) 274 return; 275 // This can only happen for orphan DocumentType nodes. 276 Document* document = node->document(); 277 if (!node->document()) 278 return; 279 280 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 281 Vector<EventListenerInfo> listenersArray; 282 host->getEventListenersImpl(node, listenersArray); 283 284 v8::Local<v8::Object> result = v8::Object::New(); 285 for (size_t i = 0; i < listenersArray.size(); ++i) { 286 v8::Handle<v8::Array> listeners = getJSListenerFunctions(document, listenersArray[i]); 287 if (!listeners->Length()) 288 continue; 289 AtomicString eventType = listenersArray[i].eventType; 290 result->Set(v8String(eventType, args.GetIsolate()), listeners); 291 } 292 293 v8SetReturnValue(args, result); 294 } 295 296 void V8InjectedScriptHost::inspectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 297 { 298 if (args.Length() < 2) 299 return; 300 301 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 302 ScriptValue object(args[0]); 303 ScriptValue hints(args[1]); 304 host->inspectImpl(object.toJSONValue(ScriptState::current()), hints.toJSONValue(ScriptState::current())); 305 } 306 307 void V8InjectedScriptHost::databaseIdMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 308 { 309 if (args.Length() > 0 && V8Database::HasInstance(args[0], args.GetIsolate(), worldType(args.GetIsolate()))) { 310 Database* database = V8Database::toNative(v8::Handle<v8::Object>::Cast(args[0])); 311 if (database) { 312 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); { 313 v8SetReturnValueStringOrUndefined(args, host->databaseIdImpl(database), args.GetIsolate()); 314 return; 315 } 316 } 317 } 318 } 319 320 void V8InjectedScriptHost::storageIdMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 321 { 322 if (args.Length() > 0 && V8Storage::HasInstance(args[0], args.GetIsolate(), worldType(args.GetIsolate()))) { 323 Storage* storage = V8Storage::toNative(v8::Handle<v8::Object>::Cast(args[0])); 324 if (storage) { 325 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 326 v8SetReturnValueStringOrUndefined(args, host->storageIdImpl(storage), args.GetIsolate()); 327 return; 328 } 329 } 330 } 331 332 void V8InjectedScriptHost::evaluateMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 333 { 334 if (args.Length() < 1) { 335 v8::ThrowException(v8::Exception::Error(v8::String::New("One argument expected."))); 336 return; 337 } 338 339 v8::Handle<v8::String> expression = args[0]->ToString(); 340 if (expression.IsEmpty()) { 341 v8::ThrowException(v8::Exception::Error(v8::String::New("The argument must be a string."))); 342 return; 343 } 344 345 ASSERT(!v8::Context::GetCurrent().IsEmpty()); 346 v8::TryCatch tryCatch; 347 v8::Handle<v8::Value> result = V8ScriptRunner::compileAndRunInternalScript(expression, args.GetIsolate()); 348 if (tryCatch.HasCaught()) { 349 v8SetReturnValue(args, tryCatch.ReThrow()); 350 return; 351 } 352 v8SetReturnValue(args, result); 353 } 354 355 void V8InjectedScriptHost::setFunctionVariableValueMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 356 { 357 v8::Handle<v8::Value> functionValue = args[0]; 358 int scopeIndex = args[1]->Int32Value(); 359 String variableName = toWebCoreStringWithUndefinedOrNullCheck(args[2]); 360 v8::Handle<v8::Value> newValue = args[3]; 361 362 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 363 ScriptDebugServer& debugServer = host->scriptDebugServer(); 364 v8SetReturnValue(args, debugServer.setFunctionVariableValue(functionValue, scopeIndex, variableName, newValue)); 365 } 366 367 static bool getFunctionLocation(const v8::FunctionCallbackInfo<v8::Value>& args, String* scriptId, int* lineNumber, int* columnNumber) 368 { 369 if (args.Length() < 1) 370 return false; 371 v8::Handle<v8::Value> fn = args[0]; 372 if (!fn->IsFunction()) 373 return false; 374 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(fn); 375 *lineNumber = function->GetScriptLineNumber(); 376 *columnNumber = function->GetScriptColumnNumber(); 377 if (*lineNumber == v8::Function::kLineOffsetNotFound || *columnNumber == v8::Function::kLineOffsetNotFound) 378 return false; 379 *scriptId = toWebCoreStringWithUndefinedOrNullCheck(function->GetScriptId()); 380 return true; 381 } 382 383 void V8InjectedScriptHost::debugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 384 { 385 String scriptId; 386 int lineNumber; 387 int columnNumber; 388 if (!getFunctionLocation(args, &scriptId, &lineNumber, &columnNumber)) 389 return; 390 391 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 392 host->debugFunction(scriptId, lineNumber, columnNumber); 393 } 394 395 void V8InjectedScriptHost::undebugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 396 { 397 String scriptId; 398 int lineNumber; 399 int columnNumber; 400 if (!getFunctionLocation(args, &scriptId, &lineNumber, &columnNumber)) 401 return; 402 403 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 404 host->undebugFunction(scriptId, lineNumber, columnNumber); 405 } 406 407 void V8InjectedScriptHost::monitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 408 { 409 String scriptId; 410 int lineNumber; 411 int columnNumber; 412 if (!getFunctionLocation(args, &scriptId, &lineNumber, &columnNumber)) 413 return; 414 415 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(args[0]); 416 v8::Handle<v8::Value> name; 417 if (args.Length() > 0 && args[0]->IsFunction()) { 418 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(args[0]); 419 name = function->GetName(); 420 if (!name->IsString() || !v8::Handle<v8::String>::Cast(name)->Length()) 421 name = function->GetInferredName(); 422 } 423 424 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 425 host->monitorFunction(scriptId, lineNumber, columnNumber, toWebCoreStringWithUndefinedOrNullCheck(name)); 426 } 427 428 void V8InjectedScriptHost::unmonitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) 429 { 430 String scriptId; 431 int lineNumber; 432 int columnNumber; 433 if (!getFunctionLocation(args, &scriptId, &lineNumber, &columnNumber)) 434 return; 435 436 InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); 437 host->unmonitorFunction(scriptId, lineNumber, columnNumber); 438 } 439 440 } // namespace WebCore 441