1 | /* |
2 | * Copyright (C) 2013 Apple Inc. All rights reserved. |
3 | * Copyright (C) 2012 Google 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 "InjectedScript.h" |
34 | |
35 | #include "JSCInlines.h" |
36 | #include "JSLock.h" |
37 | #include "ScriptFunctionCall.h" |
38 | #include "ScriptObject.h" |
39 | #include <wtf/JSONValues.h> |
40 | #include <wtf/Vector.h> |
41 | #include <wtf/text/WTFString.h> |
42 | |
43 | namespace Inspector { |
44 | |
45 | InjectedScript::InjectedScript() |
46 | : InjectedScriptBase("InjectedScript"_s ) |
47 | { |
48 | } |
49 | |
50 | InjectedScript::InjectedScript(Deprecated::ScriptObject injectedScriptObject, InspectorEnvironment* environment) |
51 | : InjectedScriptBase("InjectedScript"_s , injectedScriptObject, environment) |
52 | { |
53 | } |
54 | |
55 | InjectedScript::~InjectedScript() |
56 | { |
57 | } |
58 | |
59 | void InjectedScript::execute(ErrorString& errorString, const String& functionString, ExecuteOptions&& options, RefPtr<Protocol::Runtime::RemoteObject>& result, Optional<bool>& wasThrown, Optional<int>& savedResultIndex) |
60 | { |
61 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "execute"_s , inspectorEnvironment()->functionCallHandler()); |
62 | function.appendArgument(functionString); |
63 | function.appendArgument(options.objectGroup); |
64 | function.appendArgument(options.includeCommandLineAPI); |
65 | function.appendArgument(options.returnByValue); |
66 | function.appendArgument(options.generatePreview); |
67 | function.appendArgument(options.saveResult); |
68 | function.appendArgument(arrayFromVector(WTFMove(options.args))); |
69 | makeEvalCall(errorString, function, result, wasThrown, savedResultIndex); |
70 | } |
71 | |
72 | void InjectedScript::evaluate(ErrorString& errorString, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, Optional<bool>& wasThrown, Optional<int>& savedResultIndex) |
73 | { |
74 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "evaluate"_s , inspectorEnvironment()->functionCallHandler()); |
75 | function.appendArgument(expression); |
76 | function.appendArgument(objectGroup); |
77 | function.appendArgument(includeCommandLineAPI); |
78 | function.appendArgument(returnByValue); |
79 | function.appendArgument(generatePreview); |
80 | function.appendArgument(saveResult); |
81 | makeEvalCall(errorString, function, result, wasThrown, savedResultIndex); |
82 | } |
83 | |
84 | void InjectedScript::awaitPromise(const String& promiseObjectId, bool returnByValue, bool generatePreview, bool saveResult, AsyncCallCallback&& callback) |
85 | { |
86 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "awaitPromise"_s , inspectorEnvironment()->functionCallHandler()); |
87 | function.appendArgument(promiseObjectId); |
88 | function.appendArgument(returnByValue); |
89 | function.appendArgument(generatePreview); |
90 | function.appendArgument(saveResult); |
91 | makeAsyncCall(function, WTFMove(callback)); |
92 | } |
93 | |
94 | void InjectedScript::callFunctionOn(ErrorString& errorString, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Protocol::Runtime::RemoteObject>& result, Optional<bool>& wasThrown) |
95 | { |
96 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "callFunctionOn"_s , inspectorEnvironment()->functionCallHandler()); |
97 | function.appendArgument(objectId); |
98 | function.appendArgument(expression); |
99 | function.appendArgument(arguments); |
100 | function.appendArgument(returnByValue); |
101 | function.appendArgument(generatePreview); |
102 | |
103 | Optional<int> savedResultIndex; |
104 | makeEvalCall(errorString, function, result, wasThrown, savedResultIndex); |
105 | ASSERT(!savedResultIndex); |
106 | } |
107 | |
108 | void InjectedScript::evaluateOnCallFrame(ErrorString& errorString, JSC::JSValue callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, Optional<bool>& wasThrown, Optional<int>& savedResultIndex) |
109 | { |
110 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "evaluateOnCallFrame"_s , inspectorEnvironment()->functionCallHandler()); |
111 | function.appendArgument(callFrames); |
112 | function.appendArgument(callFrameId); |
113 | function.appendArgument(expression); |
114 | function.appendArgument(objectGroup); |
115 | function.appendArgument(includeCommandLineAPI); |
116 | function.appendArgument(returnByValue); |
117 | function.appendArgument(generatePreview); |
118 | function.appendArgument(saveResult); |
119 | makeEvalCall(errorString, function, result, wasThrown, savedResultIndex); |
120 | } |
121 | |
122 | void InjectedScript::getFunctionDetails(ErrorString& errorString, const String& functionId, RefPtr<Protocol::Debugger::FunctionDetails>& result) |
123 | { |
124 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "getFunctionDetails"_s , inspectorEnvironment()->functionCallHandler()); |
125 | function.appendArgument(functionId); |
126 | |
127 | RefPtr<JSON::Value> resultValue = makeCall(function); |
128 | if (!resultValue || resultValue->type() != JSON::Value::Type::Object) { |
129 | if (!resultValue->asString(errorString)) |
130 | errorString = "Internal error"_s ; |
131 | return; |
132 | } |
133 | |
134 | result = BindingTraits<Protocol::Debugger::FunctionDetails>::runtimeCast(WTFMove(resultValue)); |
135 | } |
136 | |
137 | void InjectedScript::functionDetails(ErrorString& errorString, JSC::JSValue value, RefPtr<Protocol::Debugger::FunctionDetails>& result) |
138 | { |
139 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "functionDetails"_s , inspectorEnvironment()->functionCallHandler()); |
140 | function.appendArgument(value); |
141 | |
142 | RefPtr<JSON::Value> resultValue = makeCall(function); |
143 | if (!resultValue || resultValue->type() != JSON::Value::Type::Object) { |
144 | if (!resultValue->asString(errorString)) |
145 | errorString = "Internal error"_s ; |
146 | return; |
147 | } |
148 | |
149 | result = BindingTraits<Protocol::Debugger::FunctionDetails>::runtimeCast(WTFMove(resultValue)); |
150 | } |
151 | |
152 | void InjectedScript::getPreview(ErrorString& errorString, const String& objectId, RefPtr<Protocol::Runtime::ObjectPreview>& result) |
153 | { |
154 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "getPreview"_s , inspectorEnvironment()->functionCallHandler()); |
155 | function.appendArgument(objectId); |
156 | |
157 | RefPtr<JSON::Value> resultValue = makeCall(function); |
158 | if (!resultValue || resultValue->type() != JSON::Value::Type::Object) { |
159 | if (!resultValue->asString(errorString)) |
160 | errorString = "Internal error"_s ; |
161 | return; |
162 | } |
163 | |
164 | result = BindingTraits<Protocol::Runtime::ObjectPreview>::runtimeCast(WTFMove(resultValue)); |
165 | } |
166 | |
167 | void InjectedScript::getProperties(ErrorString& errorString, const String& objectId, bool ownProperties, bool generatePreview, RefPtr<JSON::ArrayOf<Protocol::Runtime::PropertyDescriptor>>& properties) |
168 | { |
169 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "getProperties"_s , inspectorEnvironment()->functionCallHandler()); |
170 | function.appendArgument(objectId); |
171 | function.appendArgument(ownProperties); |
172 | function.appendArgument(generatePreview); |
173 | |
174 | RefPtr<JSON::Value> result = makeCall(function); |
175 | if (!result || result->type() != JSON::Value::Type::Array) { |
176 | errorString = "Internal error"_s ; |
177 | return; |
178 | } |
179 | |
180 | properties = BindingTraits<JSON::ArrayOf<Protocol::Runtime::PropertyDescriptor>>::runtimeCast(WTFMove(result)); |
181 | } |
182 | |
183 | void InjectedScript::getDisplayableProperties(ErrorString& errorString, const String& objectId, bool generatePreview, RefPtr<JSON::ArrayOf<Protocol::Runtime::PropertyDescriptor>>& properties) |
184 | { |
185 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "getDisplayableProperties"_s , inspectorEnvironment()->functionCallHandler()); |
186 | function.appendArgument(objectId); |
187 | function.appendArgument(generatePreview); |
188 | |
189 | RefPtr<JSON::Value> result = makeCall(function); |
190 | if (!result || result->type() != JSON::Value::Type::Array) { |
191 | errorString = "Internal error"_s ; |
192 | return; |
193 | } |
194 | |
195 | properties = BindingTraits<JSON::ArrayOf<Protocol::Runtime::PropertyDescriptor>>::runtimeCast(WTFMove(result)); |
196 | } |
197 | |
198 | void InjectedScript::getInternalProperties(ErrorString& errorString, const String& objectId, bool generatePreview, RefPtr<JSON::ArrayOf<Protocol::Runtime::InternalPropertyDescriptor>>& properties) |
199 | { |
200 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "getInternalProperties"_s , inspectorEnvironment()->functionCallHandler()); |
201 | function.appendArgument(objectId); |
202 | function.appendArgument(generatePreview); |
203 | |
204 | RefPtr<JSON::Value> result = makeCall(function); |
205 | if (!result || result->type() != JSON::Value::Type::Array) { |
206 | errorString = "Internal error"_s ; |
207 | return; |
208 | } |
209 | |
210 | auto array = BindingTraits<JSON::ArrayOf<Protocol::Runtime::InternalPropertyDescriptor>>::runtimeCast(WTFMove(result)); |
211 | properties = array->length() > 0 ? array : nullptr; |
212 | } |
213 | |
214 | void InjectedScript::getCollectionEntries(ErrorString& errorString, const String& objectId, const String& objectGroup, int startIndex, int numberToFetch, RefPtr<JSON::ArrayOf<Protocol::Runtime::CollectionEntry>>& entries) |
215 | { |
216 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "getCollectionEntries"_s , inspectorEnvironment()->functionCallHandler()); |
217 | function.appendArgument(objectId); |
218 | function.appendArgument(objectGroup); |
219 | function.appendArgument(startIndex); |
220 | function.appendArgument(numberToFetch); |
221 | |
222 | RefPtr<JSON::Value> result = makeCall(function); |
223 | if (!result || result->type() != JSON::Value::Type::Array) { |
224 | errorString = "Internal error"_s ; |
225 | return; |
226 | } |
227 | |
228 | entries = BindingTraits<JSON::ArrayOf<Protocol::Runtime::CollectionEntry>>::runtimeCast(WTFMove(result)); |
229 | } |
230 | |
231 | void InjectedScript::saveResult(ErrorString& errorString, const String& callArgumentJSON, Optional<int>& savedResultIndex) |
232 | { |
233 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "saveResult"_s , inspectorEnvironment()->functionCallHandler()); |
234 | function.appendArgument(callArgumentJSON); |
235 | |
236 | RefPtr<JSON::Value> result = makeCall(function); |
237 | if (!result || result->type() != JSON::Value::Type::Integer) { |
238 | errorString = "Internal error"_s ; |
239 | return; |
240 | } |
241 | |
242 | int resultIndex = 0; |
243 | if (result->asInteger(resultIndex) && resultIndex > 0) |
244 | savedResultIndex = resultIndex; |
245 | } |
246 | |
247 | Ref<JSON::ArrayOf<Protocol::Debugger::CallFrame>> InjectedScript::wrapCallFrames(JSC::JSValue callFrames) const |
248 | { |
249 | ASSERT(!hasNoValue()); |
250 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "wrapCallFrames"_s , inspectorEnvironment()->functionCallHandler()); |
251 | function.appendArgument(callFrames); |
252 | |
253 | bool hadException = false; |
254 | auto callFramesValue = callFunctionWithEvalEnabled(function, hadException); |
255 | if (!callFramesValue) |
256 | return JSON::ArrayOf<Protocol::Debugger::CallFrame>::create(); |
257 | ASSERT(!hadException); |
258 | RefPtr<JSON::Value> result = toInspectorValue(*scriptState(), callFramesValue); |
259 | if (result->type() == JSON::Value::Type::Array) |
260 | return BindingTraits<JSON::ArrayOf<Protocol::Debugger::CallFrame>>::runtimeCast(WTFMove(result)).releaseNonNull(); |
261 | |
262 | return JSON::ArrayOf<Protocol::Debugger::CallFrame>::create(); |
263 | } |
264 | |
265 | RefPtr<Protocol::Runtime::RemoteObject> InjectedScript::wrapObject(JSC::JSValue value, const String& groupName, bool generatePreview) const |
266 | { |
267 | ASSERT(!hasNoValue()); |
268 | Deprecated::ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapObject"_s , inspectorEnvironment()->functionCallHandler()); |
269 | wrapFunction.appendArgument(value); |
270 | wrapFunction.appendArgument(groupName); |
271 | wrapFunction.appendArgument(hasAccessToInspectedScriptState()); |
272 | wrapFunction.appendArgument(generatePreview); |
273 | |
274 | bool hadException = false; |
275 | auto r = callFunctionWithEvalEnabled(wrapFunction, hadException); |
276 | if (hadException) |
277 | return nullptr; |
278 | |
279 | RefPtr<JSON::Object> resultObject; |
280 | bool castSucceeded = toInspectorValue(*scriptState(), r)->asObject(resultObject); |
281 | ASSERT_UNUSED(castSucceeded, castSucceeded); |
282 | |
283 | return BindingTraits<Protocol::Runtime::RemoteObject>::runtimeCast(resultObject); |
284 | } |
285 | |
286 | RefPtr<Protocol::Runtime::RemoteObject> InjectedScript::wrapJSONString(const String& json, const String& groupName, bool generatePreview) const |
287 | { |
288 | ASSERT(!hasNoValue()); |
289 | Deprecated::ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapJSONString"_s , inspectorEnvironment()->functionCallHandler()); |
290 | wrapFunction.appendArgument(json); |
291 | wrapFunction.appendArgument(groupName); |
292 | wrapFunction.appendArgument(generatePreview); |
293 | |
294 | bool hadException = false; |
295 | auto evalResult = callFunctionWithEvalEnabled(wrapFunction, hadException); |
296 | if (hadException) |
297 | return nullptr; |
298 | |
299 | if (evalResult.isNull()) |
300 | return nullptr; |
301 | |
302 | RefPtr<JSON::Object> resultObject; |
303 | bool castSucceeded = toInspectorValue(*scriptState(), evalResult)->asObject(resultObject); |
304 | ASSERT_UNUSED(castSucceeded, castSucceeded); |
305 | |
306 | return BindingTraits<Protocol::Runtime::RemoteObject>::runtimeCast(resultObject); |
307 | } |
308 | |
309 | RefPtr<Protocol::Runtime::RemoteObject> InjectedScript::wrapTable(JSC::JSValue table, JSC::JSValue columns) const |
310 | { |
311 | ASSERT(!hasNoValue()); |
312 | Deprecated::ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapTable"_s , inspectorEnvironment()->functionCallHandler()); |
313 | wrapFunction.appendArgument(hasAccessToInspectedScriptState()); |
314 | wrapFunction.appendArgument(table); |
315 | if (!columns) |
316 | wrapFunction.appendArgument(false); |
317 | else |
318 | wrapFunction.appendArgument(columns); |
319 | |
320 | bool hadException = false; |
321 | auto r = callFunctionWithEvalEnabled(wrapFunction, hadException); |
322 | if (hadException) |
323 | return nullptr; |
324 | |
325 | RefPtr<JSON::Object> resultObject; |
326 | bool castSucceeded = toInspectorValue(*scriptState(), r)->asObject(resultObject); |
327 | ASSERT_UNUSED(castSucceeded, castSucceeded); |
328 | |
329 | return BindingTraits<Protocol::Runtime::RemoteObject>::runtimeCast(resultObject); |
330 | } |
331 | |
332 | RefPtr<Protocol::Runtime::ObjectPreview> InjectedScript::previewValue(JSC::JSValue value) const |
333 | { |
334 | ASSERT(!hasNoValue()); |
335 | Deprecated::ScriptFunctionCall wrapFunction(injectedScriptObject(), "previewValue"_s , inspectorEnvironment()->functionCallHandler()); |
336 | wrapFunction.appendArgument(value); |
337 | |
338 | bool hadException = false; |
339 | auto r = callFunctionWithEvalEnabled(wrapFunction, hadException); |
340 | if (hadException) |
341 | return nullptr; |
342 | |
343 | RefPtr<JSON::Object> resultObject; |
344 | bool castSucceeded = toInspectorValue(*scriptState(), r)->asObject(resultObject); |
345 | ASSERT_UNUSED(castSucceeded, castSucceeded); |
346 | |
347 | return BindingTraits<Protocol::Runtime::ObjectPreview>::runtimeCast(resultObject); |
348 | } |
349 | |
350 | void InjectedScript::setEventValue(JSC::JSValue value) |
351 | { |
352 | ASSERT(!hasNoValue()); |
353 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "setEventValue"_s , inspectorEnvironment()->functionCallHandler()); |
354 | function.appendArgument(value); |
355 | makeCall(function); |
356 | } |
357 | |
358 | void InjectedScript::clearEventValue() |
359 | { |
360 | ASSERT(!hasNoValue()); |
361 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "clearEventValue"_s , inspectorEnvironment()->functionCallHandler()); |
362 | makeCall(function); |
363 | } |
364 | |
365 | void InjectedScript::setExceptionValue(JSC::JSValue value) |
366 | { |
367 | ASSERT(!hasNoValue()); |
368 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "setExceptionValue"_s , inspectorEnvironment()->functionCallHandler()); |
369 | function.appendArgument(value); |
370 | makeCall(function); |
371 | } |
372 | |
373 | void InjectedScript::clearExceptionValue() |
374 | { |
375 | ASSERT(!hasNoValue()); |
376 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "clearExceptionValue"_s , inspectorEnvironment()->functionCallHandler()); |
377 | makeCall(function); |
378 | } |
379 | |
380 | JSC::JSValue InjectedScript::findObjectById(const String& objectId) const |
381 | { |
382 | ASSERT(!hasNoValue()); |
383 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "findObjectById"_s , inspectorEnvironment()->functionCallHandler()); |
384 | function.appendArgument(objectId); |
385 | |
386 | bool hadException = false; |
387 | auto resultValue = callFunctionWithEvalEnabled(function, hadException); |
388 | ASSERT(!hadException); |
389 | |
390 | return resultValue; |
391 | } |
392 | |
393 | void InjectedScript::inspectObject(JSC::JSValue value) |
394 | { |
395 | ASSERT(!hasNoValue()); |
396 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "inspectObject"_s , inspectorEnvironment()->functionCallHandler()); |
397 | function.appendArgument(value); |
398 | makeCall(function); |
399 | } |
400 | |
401 | void InjectedScript::releaseObject(const String& objectId) |
402 | { |
403 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "releaseObject"_s , inspectorEnvironment()->functionCallHandler()); |
404 | function.appendArgument(objectId); |
405 | makeCall(function); |
406 | } |
407 | |
408 | void InjectedScript::releaseObjectGroup(const String& objectGroup) |
409 | { |
410 | ASSERT(!hasNoValue()); |
411 | Deprecated::ScriptFunctionCall releaseFunction(injectedScriptObject(), "releaseObjectGroup"_s , inspectorEnvironment()->functionCallHandler()); |
412 | releaseFunction.appendArgument(objectGroup); |
413 | |
414 | bool hadException = false; |
415 | callFunctionWithEvalEnabled(releaseFunction, hadException); |
416 | ASSERT(!hadException); |
417 | } |
418 | |
419 | JSC::JSValue InjectedScript::arrayFromVector(Vector<JSC::JSValue>&& vector) |
420 | { |
421 | JSC::ExecState* execState = scriptState(); |
422 | if (!execState) |
423 | return JSC::jsUndefined(); |
424 | |
425 | JSC::JSLockHolder lock(execState); |
426 | |
427 | JSC::JSArray* array = JSC::constructEmptyArray(execState, nullptr); |
428 | if (!array) |
429 | return JSC::jsUndefined(); |
430 | |
431 | for (auto& item : vector) |
432 | array->putDirectIndex(execState, array->length(), item); |
433 | |
434 | return array; |
435 | } |
436 | |
437 | } // namespace Inspector |
438 | |
439 | |