• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "bindings/core/v8/V8InjectedScriptHost.h"
33 
34 #include "bindings/core/v8/V8EventTarget.h"
35 #include "bindings/core/v8/V8HTMLAllCollection.h"
36 #include "bindings/core/v8/V8HTMLCollection.h"
37 #include "bindings/core/v8/V8Node.h"
38 #include "bindings/core/v8/V8NodeList.h"
39 #include "bindings/core/v8/V8Storage.h"
40 #include "bindings/modules/v8/V8Database.h"
41 #include "bindings/v8/BindingSecurity.h"
42 #include "bindings/v8/ExceptionState.h"
43 #include "bindings/v8/ScriptDebugServer.h"
44 #include "bindings/v8/ScriptValue.h"
45 #include "bindings/v8/V8AbstractEventListener.h"
46 #include "bindings/v8/V8Binding.h"
47 #include "bindings/v8/V8ScriptRunner.h"
48 #include "bindings/v8/custom/V8Float32ArrayCustom.h"
49 #include "bindings/v8/custom/V8Float64ArrayCustom.h"
50 #include "bindings/v8/custom/V8Int16ArrayCustom.h"
51 #include "bindings/v8/custom/V8Int32ArrayCustom.h"
52 #include "bindings/v8/custom/V8Int8ArrayCustom.h"
53 #include "bindings/v8/custom/V8Uint16ArrayCustom.h"
54 #include "bindings/v8/custom/V8Uint32ArrayCustom.h"
55 #include "bindings/v8/custom/V8Uint8ArrayCustom.h"
56 #include "bindings/v8/custom/V8Uint8ClampedArrayCustom.h"
57 #include "core/events/EventTarget.h"
58 #include "core/frame/LocalDOMWindow.h"
59 #include "core/inspector/InjectedScript.h"
60 #include "core/inspector/InjectedScriptHost.h"
61 #include "core/inspector/InspectorDOMAgent.h"
62 #include "modules/webdatabase/Database.h"
63 #include "platform/JSONValues.h"
64 
65 namespace WebCore {
66 
scriptValueAsNode(ScriptState * scriptState,ScriptValue value)67 Node* InjectedScriptHost::scriptValueAsNode(ScriptState* scriptState, ScriptValue value)
68 {
69     ScriptState::Scope scope(scriptState);
70     if (!value.isObject() || value.isNull())
71         return 0;
72     return V8Node::toNative(v8::Handle<v8::Object>::Cast(value.v8Value()));
73 }
74 
nodeAsScriptValue(ScriptState * scriptState,Node * node)75 ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* scriptState, Node* node)
76 {
77     ScriptState::Scope scope(scriptState);
78     v8::Isolate* isolate = scriptState->isolate();
79     ExceptionState exceptionState(ExceptionState::ExecutionContext, "nodeAsScriptValue", "InjectedScriptHost", scriptState->context()->Global(), isolate);
80     if (!BindingSecurity::shouldAllowAccessToNode(isolate, node, exceptionState))
81         return ScriptValue(scriptState, v8::Null(isolate));
82     return ScriptValue(scriptState, toV8(node, scriptState->context()->Global(), isolate));
83 }
84 
inspectedObjectMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)85 void V8InjectedScriptHost::inspectedObjectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
86 {
87     if (info.Length() < 1)
88         return;
89 
90     if (!info[0]->IsInt32()) {
91         throwTypeError("argument has to be an integer", info.GetIsolate());
92         return;
93     }
94 
95     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
96     InjectedScriptHost::InspectableObject* object = host->inspectedObject(info[0]->ToInt32()->Value());
97     v8SetReturnValue(info, object->get(ScriptState::current(info.GetIsolate())).v8Value());
98 }
99 
internalConstructorNameMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)100 void V8InjectedScriptHost::internalConstructorNameMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
101 {
102     if (info.Length() < 1)
103         return;
104 
105     if (!info[0]->IsObject())
106         return;
107 
108     v8SetReturnValue(info, info[0]->ToObject()->GetConstructorName());
109 }
110 
isHTMLAllCollectionMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)111 void V8InjectedScriptHost::isHTMLAllCollectionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
112 {
113     if (info.Length() < 1)
114         return;
115 
116     if (!info[0]->IsObject()) {
117         v8SetReturnValue(info, false);
118         return;
119     }
120 
121     v8SetReturnValue(info, V8HTMLAllCollection::hasInstance(info[0], info.GetIsolate()));
122 }
123 
typeMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)124 void V8InjectedScriptHost::typeMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
125 {
126     if (info.Length() < 1)
127         return;
128     v8::Isolate* isolate = info.GetIsolate();
129 
130     v8::Handle<v8::Value> value = info[0];
131     if (value->IsString()) {
132         v8SetReturnValue(info, v8AtomicString(isolate, "string"));
133         return;
134     }
135     if (value->IsArray()) {
136         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
137         return;
138     }
139     if (value->IsBoolean()) {
140         v8SetReturnValue(info, v8AtomicString(isolate, "boolean"));
141         return;
142     }
143     if (value->IsNumber()) {
144         v8SetReturnValue(info, v8AtomicString(isolate, "number"));
145         return;
146     }
147     if (value->IsDate()) {
148         v8SetReturnValue(info, v8AtomicString(isolate, "date"));
149         return;
150     }
151     if (value->IsRegExp()) {
152         v8SetReturnValue(info, v8AtomicString(isolate, "regexp"));
153         return;
154     }
155     if (V8Node::hasInstance(value, isolate)) {
156         v8SetReturnValue(info, v8AtomicString(isolate, "node"));
157         return;
158     }
159     if (V8NodeList::hasInstance(value, isolate)) {
160         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
161         return;
162     }
163     if (V8HTMLCollection::hasInstance(value, isolate)) {
164         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
165         return;
166     }
167     if (V8Int8Array::hasInstance(value, isolate) || V8Int16Array::hasInstance(value, isolate) || V8Int32Array::hasInstance(value, isolate)) {
168         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
169         return;
170     }
171     if (V8Uint8Array::hasInstance(value, isolate) || V8Uint16Array::hasInstance(value, isolate) || V8Uint32Array::hasInstance(value, isolate)) {
172         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
173         return;
174     }
175     if (V8Float32Array::hasInstance(value, isolate) || V8Float64Array::hasInstance(value, isolate)) {
176         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
177         return;
178     }
179     if (V8Uint8ClampedArray::hasInstance(value, isolate)) {
180         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
181         return;
182     }
183 }
184 
setFunctionName(v8::Handle<v8::Object> & result,const v8::Handle<v8::Value> & value,v8::Isolate * isolate)185 static bool setFunctionName(v8::Handle<v8::Object>& result, const v8::Handle<v8::Value>& value, v8::Isolate* isolate)
186 {
187     if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length()) {
188         result->Set(v8AtomicString(isolate, "functionName"), value);
189         return true;
190     }
191     return false;
192 }
193 
functionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)194 void V8InjectedScriptHost::functionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
195 {
196     if (info.Length() < 1)
197         return;
198 
199     v8::Isolate* isolate = info.GetIsolate();
200 
201     v8::Handle<v8::Value> value = info[0];
202     if (!value->IsFunction())
203         return;
204     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
205     int lineNumber = function->GetScriptLineNumber();
206     int columnNumber = function->GetScriptColumnNumber();
207 
208     v8::Local<v8::Object> location = v8::Object::New(isolate);
209     location->Set(v8AtomicString(isolate, "lineNumber"), v8::Integer::New(isolate, lineNumber));
210     location->Set(v8AtomicString(isolate, "columnNumber"), v8::Integer::New(isolate, columnNumber));
211     location->Set(v8AtomicString(isolate, "scriptId"), v8::Integer::New(isolate, function->ScriptId())->ToString());
212 
213     v8::Local<v8::Object> result = v8::Object::New(isolate);
214     result->Set(v8AtomicString(isolate, "location"), location);
215 
216     if (!setFunctionName(result, function->GetDisplayName(), isolate)
217         && !setFunctionName(result, function->GetName(), isolate)
218         && !setFunctionName(result, function->GetInferredName(), isolate))
219         result->Set(v8AtomicString(isolate, "functionName"), v8AtomicString(isolate, ""));
220 
221     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
222     ScriptDebugServer& debugServer = host->scriptDebugServer();
223     v8::Handle<v8::Value> scopes = debugServer.functionScopes(function);
224     if (!scopes.IsEmpty() && scopes->IsArray())
225         result->Set(v8AtomicString(isolate, "rawScopes"), scopes);
226 
227     v8SetReturnValue(info, result);
228 }
229 
getInternalPropertiesMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)230 void V8InjectedScriptHost::getInternalPropertiesMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
231 {
232     if (info.Length() < 1)
233         return;
234 
235     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(info[0]);
236 
237     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
238     ScriptDebugServer& debugServer = host->scriptDebugServer();
239     v8SetReturnValue(info, debugServer.getInternalProperties(object));
240 }
241 
getJSListenerFunctions(ExecutionContext * executionContext,const EventListenerInfo & listenerInfo,v8::Isolate * isolate)242 static v8::Handle<v8::Array> getJSListenerFunctions(ExecutionContext* executionContext, const EventListenerInfo& listenerInfo, v8::Isolate* isolate)
243 {
244     v8::Local<v8::Array> result = v8::Array::New(isolate);
245     size_t handlersCount = listenerInfo.eventListenerVector.size();
246     for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) {
247         RefPtr<EventListener> listener = listenerInfo.eventListenerVector[i].listener;
248         if (listener->type() != EventListener::JSEventListenerType) {
249             ASSERT_NOT_REACHED();
250             continue;
251         }
252         V8AbstractEventListener* v8Listener = static_cast<V8AbstractEventListener*>(listener.get());
253         v8::Local<v8::Context> context = toV8Context(executionContext, v8Listener->world());
254         // Hide listeners from other contexts.
255         if (context != isolate->GetCurrentContext())
256             continue;
257         v8::Local<v8::Object> function;
258         {
259             // getListenerObject() may cause JS in the event attribute to get compiled, potentially unsuccessfully.
260             v8::TryCatch block;
261             function = v8Listener->getListenerObject(executionContext);
262             if (block.HasCaught())
263                 continue;
264         }
265         ASSERT(!function.IsEmpty());
266         v8::Local<v8::Object> listenerEntry = v8::Object::New(isolate);
267         listenerEntry->Set(v8AtomicString(isolate, "listener"), function);
268         listenerEntry->Set(v8AtomicString(isolate, "useCapture"), v8::Boolean::New(isolate, listenerInfo.eventListenerVector[i].useCapture));
269         result->Set(v8::Number::New(isolate, outputIndex++), listenerEntry);
270     }
271     return result;
272 }
273 
getEventListenersMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)274 void V8InjectedScriptHost::getEventListenersMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
275 {
276     if (info.Length() < 1)
277         return;
278 
279 
280     v8::Local<v8::Value> value = info[0];
281     EventTarget* target = V8EventTarget::toNativeWithTypeCheck(info.GetIsolate(), value);
282 
283     // We need to handle a LocalDOMWindow specially, because a LocalDOMWindow wrapper exists on a prototype chain.
284     if (!target)
285         target = toDOMWindow(value, info.GetIsolate());
286 
287     if (!target || !target->executionContext())
288         return;
289 
290     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
291     Vector<EventListenerInfo> listenersArray;
292     host->getEventListenersImpl(target, listenersArray);
293 
294     v8::Local<v8::Object> result = v8::Object::New(info.GetIsolate());
295     for (size_t i = 0; i < listenersArray.size(); ++i) {
296         v8::Handle<v8::Array> listeners = getJSListenerFunctions(target->executionContext(), listenersArray[i], info.GetIsolate());
297         if (!listeners->Length())
298             continue;
299         AtomicString eventType = listenersArray[i].eventType;
300         result->Set(v8String(info.GetIsolate(), eventType), listeners);
301     }
302 
303     v8SetReturnValue(info, result);
304 }
305 
inspectMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)306 void V8InjectedScriptHost::inspectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
307 {
308     if (info.Length() < 2)
309         return;
310 
311     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
312     ScriptState* scriptState = ScriptState::current(info.GetIsolate());
313     ScriptValue object(scriptState, info[0]);
314     ScriptValue hints(scriptState, info[1]);
315     host->inspectImpl(object.toJSONValue(scriptState), hints.toJSONValue(scriptState));
316 }
317 
evaluateMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)318 void V8InjectedScriptHost::evaluateMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
319 {
320     v8::Isolate* isolate = info.GetIsolate();
321     if (info.Length() < 1) {
322         isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected.")));
323         return;
324     }
325 
326     v8::Handle<v8::String> expression = info[0]->ToString();
327     if (expression.IsEmpty()) {
328         isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "The argument must be a string.")));
329         return;
330     }
331 
332     ASSERT(isolate->InContext());
333     v8::TryCatch tryCatch;
334     v8::Handle<v8::Value> result = V8ScriptRunner::compileAndRunInternalScript(expression, info.GetIsolate());
335     if (tryCatch.HasCaught()) {
336         v8SetReturnValue(info, tryCatch.ReThrow());
337         return;
338     }
339     v8SetReturnValue(info, result);
340 }
341 
setFunctionVariableValueMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)342 void V8InjectedScriptHost::setFunctionVariableValueMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
343 {
344     v8::Handle<v8::Value> functionValue = info[0];
345     int scopeIndex = info[1]->Int32Value();
346     String variableName = toCoreStringWithUndefinedOrNullCheck(info[2]);
347     v8::Handle<v8::Value> newValue = info[3];
348 
349     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
350     ScriptDebugServer& debugServer = host->scriptDebugServer();
351     v8SetReturnValue(info, debugServer.setFunctionVariableValue(functionValue, scopeIndex, variableName, newValue));
352 }
353 
getFunctionLocation(const v8::FunctionCallbackInfo<v8::Value> & info,String * scriptId,int * lineNumber,int * columnNumber)354 static bool getFunctionLocation(const v8::FunctionCallbackInfo<v8::Value>& info, String* scriptId, int* lineNumber, int* columnNumber)
355 {
356     if (info.Length() < 1)
357         return false;
358     v8::Handle<v8::Value> fn = info[0];
359     if (!fn->IsFunction())
360         return false;
361     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(fn);
362     *lineNumber = function->GetScriptLineNumber();
363     *columnNumber = function->GetScriptColumnNumber();
364     if (*lineNumber == v8::Function::kLineOffsetNotFound || *columnNumber == v8::Function::kLineOffsetNotFound)
365         return false;
366     *scriptId = String::number(function->ScriptId());
367     return true;
368 }
369 
debugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)370 void V8InjectedScriptHost::debugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
371 {
372     String scriptId;
373     int lineNumber;
374     int columnNumber;
375     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
376         return;
377 
378     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
379     host->debugFunction(scriptId, lineNumber, columnNumber);
380 }
381 
undebugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)382 void V8InjectedScriptHost::undebugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
383 {
384     String scriptId;
385     int lineNumber;
386     int columnNumber;
387     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
388         return;
389 
390     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
391     host->undebugFunction(scriptId, lineNumber, columnNumber);
392 }
393 
monitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)394 void V8InjectedScriptHost::monitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
395 {
396     String scriptId;
397     int lineNumber;
398     int columnNumber;
399     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
400         return;
401 
402     v8::Handle<v8::Value> name;
403     if (info.Length() > 0 && info[0]->IsFunction()) {
404         v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(info[0]);
405         name = function->GetName();
406         if (!name->IsString() || !v8::Handle<v8::String>::Cast(name)->Length())
407             name = function->GetInferredName();
408     }
409 
410     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
411     host->monitorFunction(scriptId, lineNumber, columnNumber, toCoreStringWithUndefinedOrNullCheck(name));
412 }
413 
unmonitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)414 void V8InjectedScriptHost::unmonitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
415 {
416     String scriptId;
417     int lineNumber;
418     int columnNumber;
419     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
420         return;
421 
422     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
423     host->unmonitorFunction(scriptId, lineNumber, columnNumber);
424 }
425 
suppressWarningsAndCallMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)426 void V8InjectedScriptHost::suppressWarningsAndCallMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
427 {
428     if (info.Length() < 2 || !info[0]->IsObject() || !info[1]->IsFunction())
429         return;
430 
431     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
432     ScriptDebugServer& debugServer = host->scriptDebugServer();
433     debugServer.muteWarningsAndDeprecations();
434 
435     v8::Handle<v8::Object> receiver = v8::Handle<v8::Object>::Cast(info[0]);
436     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(info[1]);
437     size_t argc = info.Length() - 2;
438     OwnPtr<v8::Handle<v8::Value>[]> argv = adoptArrayPtr(new v8::Handle<v8::Value>[argc]);
439     for (size_t i = 0; i < argc; ++i)
440         argv[i] = info[i + 2];
441 
442     v8::Local<v8::Value> result = function->Call(receiver, argc, argv.get());
443     debugServer.unmuteWarningsAndDeprecations();
444     v8SetReturnValue(info, result);
445 }
446 
447 } // namespace WebCore
448