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, int fetchStart, int fetchCount, bool generatePreview, RefPtr<JSON::ArrayOf<Protocol::Runtime::PropertyDescriptor>>& properties) |
168 | { |
169 | ASSERT(fetchStart >= 0); |
170 | ASSERT(fetchCount >= 0); |
171 | |
172 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "getProperties"_s , inspectorEnvironment()->functionCallHandler()); |
173 | function.appendArgument(objectId); |
174 | function.appendArgument(ownProperties); |
175 | function.appendArgument(fetchStart); |
176 | function.appendArgument(fetchCount); |
177 | function.appendArgument(generatePreview); |
178 | |
179 | RefPtr<JSON::Value> result = makeCall(function); |
180 | if (!result || result->type() != JSON::Value::Type::Array) { |
181 | errorString = "Internal error"_s ; |
182 | return; |
183 | } |
184 | |
185 | properties = BindingTraits<JSON::ArrayOf<Protocol::Runtime::PropertyDescriptor>>::runtimeCast(WTFMove(result)); |
186 | } |
187 | |
188 | void InjectedScript::getDisplayableProperties(ErrorString& errorString, const String& objectId, int fetchStart, int fetchCount, bool generatePreview, RefPtr<JSON::ArrayOf<Protocol::Runtime::PropertyDescriptor>>& properties) |
189 | { |
190 | ASSERT(fetchStart >= 0); |
191 | ASSERT(fetchCount >= 0); |
192 | |
193 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "getDisplayableProperties"_s , inspectorEnvironment()->functionCallHandler()); |
194 | function.appendArgument(objectId); |
195 | function.appendArgument(fetchStart); |
196 | function.appendArgument(fetchCount); |
197 | function.appendArgument(generatePreview); |
198 | |
199 | RefPtr<JSON::Value> result = makeCall(function); |
200 | if (!result || result->type() != JSON::Value::Type::Array) { |
201 | errorString = "Internal error"_s ; |
202 | return; |
203 | } |
204 | |
205 | properties = BindingTraits<JSON::ArrayOf<Protocol::Runtime::PropertyDescriptor>>::runtimeCast(WTFMove(result)); |
206 | } |
207 | |
208 | void InjectedScript::getInternalProperties(ErrorString& errorString, const String& objectId, bool generatePreview, RefPtr<JSON::ArrayOf<Protocol::Runtime::InternalPropertyDescriptor>>& properties) |
209 | { |
210 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "getInternalProperties"_s , inspectorEnvironment()->functionCallHandler()); |
211 | function.appendArgument(objectId); |
212 | function.appendArgument(generatePreview); |
213 | |
214 | RefPtr<JSON::Value> result = makeCall(function); |
215 | if (!result || result->type() != JSON::Value::Type::Array) { |
216 | errorString = "Internal error"_s ; |
217 | return; |
218 | } |
219 | |
220 | auto array = BindingTraits<JSON::ArrayOf<Protocol::Runtime::InternalPropertyDescriptor>>::runtimeCast(WTFMove(result)); |
221 | properties = array->length() > 0 ? array : nullptr; |
222 | } |
223 | |
224 | void InjectedScript::getCollectionEntries(ErrorString& errorString, const String& objectId, const String& objectGroup, int fetchStart, int fetchCount, RefPtr<JSON::ArrayOf<Protocol::Runtime::CollectionEntry>>& entries) |
225 | { |
226 | ASSERT(fetchStart >= 0); |
227 | ASSERT(fetchCount >= 0); |
228 | |
229 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "getCollectionEntries"_s , inspectorEnvironment()->functionCallHandler()); |
230 | function.appendArgument(objectId); |
231 | function.appendArgument(objectGroup); |
232 | function.appendArgument(fetchStart); |
233 | function.appendArgument(fetchCount); |
234 | |
235 | RefPtr<JSON::Value> result = makeCall(function); |
236 | if (!result || result->type() != JSON::Value::Type::Array) { |
237 | errorString = "Internal error"_s ; |
238 | return; |
239 | } |
240 | |
241 | entries = BindingTraits<JSON::ArrayOf<Protocol::Runtime::CollectionEntry>>::runtimeCast(WTFMove(result)); |
242 | } |
243 | |
244 | void InjectedScript::saveResult(ErrorString& errorString, const String& callArgumentJSON, Optional<int>& savedResultIndex) |
245 | { |
246 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "saveResult"_s , inspectorEnvironment()->functionCallHandler()); |
247 | function.appendArgument(callArgumentJSON); |
248 | |
249 | RefPtr<JSON::Value> result = makeCall(function); |
250 | if (!result || result->type() != JSON::Value::Type::Integer) { |
251 | errorString = "Internal error"_s ; |
252 | return; |
253 | } |
254 | |
255 | int resultIndex = 0; |
256 | if (result->asInteger(resultIndex) && resultIndex > 0) |
257 | savedResultIndex = resultIndex; |
258 | } |
259 | |
260 | Ref<JSON::ArrayOf<Protocol::Debugger::CallFrame>> InjectedScript::wrapCallFrames(JSC::JSValue callFrames) const |
261 | { |
262 | ASSERT(!hasNoValue()); |
263 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "wrapCallFrames"_s , inspectorEnvironment()->functionCallHandler()); |
264 | function.appendArgument(callFrames); |
265 | |
266 | auto callResult = callFunctionWithEvalEnabled(function); |
267 | ASSERT(callResult); |
268 | if (!callResult || !callResult.value()) |
269 | return JSON::ArrayOf<Protocol::Debugger::CallFrame>::create(); |
270 | |
271 | RefPtr<JSON::Value> result = toInspectorValue(globalObject(), callResult.value()); |
272 | if (result->type() == JSON::Value::Type::Array) |
273 | return BindingTraits<JSON::ArrayOf<Protocol::Debugger::CallFrame>>::runtimeCast(WTFMove(result)).releaseNonNull(); |
274 | |
275 | return JSON::ArrayOf<Protocol::Debugger::CallFrame>::create(); |
276 | } |
277 | |
278 | RefPtr<Protocol::Runtime::RemoteObject> InjectedScript::wrapObject(JSC::JSValue value, const String& groupName, bool generatePreview) const |
279 | { |
280 | ASSERT(!hasNoValue()); |
281 | Deprecated::ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapObject"_s , inspectorEnvironment()->functionCallHandler()); |
282 | wrapFunction.appendArgument(value); |
283 | wrapFunction.appendArgument(groupName); |
284 | wrapFunction.appendArgument(hasAccessToInspectedScriptState()); |
285 | wrapFunction.appendArgument(generatePreview); |
286 | |
287 | auto callResult = callFunctionWithEvalEnabled(wrapFunction); |
288 | if (!callResult) |
289 | return nullptr; |
290 | |
291 | RefPtr<JSON::Object> resultObject; |
292 | bool castSucceeded = toInspectorValue(globalObject(), callResult.value())->asObject(resultObject); |
293 | ASSERT_UNUSED(castSucceeded, castSucceeded); |
294 | |
295 | return BindingTraits<Protocol::Runtime::RemoteObject>::runtimeCast(resultObject); |
296 | } |
297 | |
298 | RefPtr<Protocol::Runtime::RemoteObject> InjectedScript::wrapJSONString(const String& json, const String& groupName, bool generatePreview) const |
299 | { |
300 | ASSERT(!hasNoValue()); |
301 | Deprecated::ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapJSONString"_s , inspectorEnvironment()->functionCallHandler()); |
302 | wrapFunction.appendArgument(json); |
303 | wrapFunction.appendArgument(groupName); |
304 | wrapFunction.appendArgument(generatePreview); |
305 | |
306 | auto callResult = callFunctionWithEvalEnabled(wrapFunction); |
307 | if (!callResult) |
308 | return nullptr; |
309 | |
310 | if (callResult.value().isNull()) |
311 | return nullptr; |
312 | |
313 | RefPtr<JSON::Object> resultObject; |
314 | bool castSucceeded = toInspectorValue(globalObject(), callResult.value())->asObject(resultObject); |
315 | ASSERT_UNUSED(castSucceeded, castSucceeded); |
316 | |
317 | return BindingTraits<Protocol::Runtime::RemoteObject>::runtimeCast(resultObject); |
318 | } |
319 | |
320 | RefPtr<Protocol::Runtime::RemoteObject> InjectedScript::wrapTable(JSC::JSValue table, JSC::JSValue columns) const |
321 | { |
322 | ASSERT(!hasNoValue()); |
323 | Deprecated::ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapTable"_s , inspectorEnvironment()->functionCallHandler()); |
324 | wrapFunction.appendArgument(hasAccessToInspectedScriptState()); |
325 | wrapFunction.appendArgument(table); |
326 | if (!columns) |
327 | wrapFunction.appendArgument(false); |
328 | else |
329 | wrapFunction.appendArgument(columns); |
330 | |
331 | auto callResult = callFunctionWithEvalEnabled(wrapFunction); |
332 | if (!callResult) |
333 | return nullptr; |
334 | |
335 | RefPtr<JSON::Object> resultObject; |
336 | bool castSucceeded = toInspectorValue(globalObject(), callResult.value())->asObject(resultObject); |
337 | ASSERT_UNUSED(castSucceeded, castSucceeded); |
338 | |
339 | return BindingTraits<Protocol::Runtime::RemoteObject>::runtimeCast(resultObject); |
340 | } |
341 | |
342 | RefPtr<Protocol::Runtime::ObjectPreview> InjectedScript::previewValue(JSC::JSValue value) const |
343 | { |
344 | ASSERT(!hasNoValue()); |
345 | Deprecated::ScriptFunctionCall wrapFunction(injectedScriptObject(), "previewValue"_s , inspectorEnvironment()->functionCallHandler()); |
346 | wrapFunction.appendArgument(value); |
347 | |
348 | auto callResult = callFunctionWithEvalEnabled(wrapFunction); |
349 | if (!callResult) |
350 | return nullptr; |
351 | |
352 | RefPtr<JSON::Object> resultObject; |
353 | bool castSucceeded = toInspectorValue(globalObject(), callResult.value())->asObject(resultObject); |
354 | ASSERT_UNUSED(castSucceeded, castSucceeded); |
355 | |
356 | return BindingTraits<Protocol::Runtime::ObjectPreview>::runtimeCast(resultObject); |
357 | } |
358 | |
359 | void InjectedScript::setEventValue(JSC::JSValue value) |
360 | { |
361 | ASSERT(!hasNoValue()); |
362 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "setEventValue"_s , inspectorEnvironment()->functionCallHandler()); |
363 | function.appendArgument(value); |
364 | makeCall(function); |
365 | } |
366 | |
367 | void InjectedScript::clearEventValue() |
368 | { |
369 | ASSERT(!hasNoValue()); |
370 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "clearEventValue"_s , inspectorEnvironment()->functionCallHandler()); |
371 | makeCall(function); |
372 | } |
373 | |
374 | void InjectedScript::setExceptionValue(JSC::JSValue value) |
375 | { |
376 | ASSERT(!hasNoValue()); |
377 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "setExceptionValue"_s , inspectorEnvironment()->functionCallHandler()); |
378 | function.appendArgument(value); |
379 | makeCall(function); |
380 | } |
381 | |
382 | void InjectedScript::clearExceptionValue() |
383 | { |
384 | ASSERT(!hasNoValue()); |
385 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "clearExceptionValue"_s , inspectorEnvironment()->functionCallHandler()); |
386 | makeCall(function); |
387 | } |
388 | |
389 | JSC::JSValue InjectedScript::findObjectById(const String& objectId) const |
390 | { |
391 | ASSERT(!hasNoValue()); |
392 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "findObjectById"_s , inspectorEnvironment()->functionCallHandler()); |
393 | function.appendArgument(objectId); |
394 | |
395 | auto callResult = callFunctionWithEvalEnabled(function); |
396 | ASSERT(callResult); |
397 | if (!callResult) |
398 | return { }; |
399 | return callResult.value(); |
400 | } |
401 | |
402 | void InjectedScript::inspectObject(JSC::JSValue value) |
403 | { |
404 | ASSERT(!hasNoValue()); |
405 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "inspectObject"_s , inspectorEnvironment()->functionCallHandler()); |
406 | function.appendArgument(value); |
407 | makeCall(function); |
408 | } |
409 | |
410 | void InjectedScript::releaseObject(const String& objectId) |
411 | { |
412 | Deprecated::ScriptFunctionCall function(injectedScriptObject(), "releaseObject"_s , inspectorEnvironment()->functionCallHandler()); |
413 | function.appendArgument(objectId); |
414 | makeCall(function); |
415 | } |
416 | |
417 | void InjectedScript::releaseObjectGroup(const String& objectGroup) |
418 | { |
419 | ASSERT(!hasNoValue()); |
420 | Deprecated::ScriptFunctionCall releaseFunction(injectedScriptObject(), "releaseObjectGroup"_s , inspectorEnvironment()->functionCallHandler()); |
421 | releaseFunction.appendArgument(objectGroup); |
422 | |
423 | auto callResult = callFunctionWithEvalEnabled(releaseFunction); |
424 | ASSERT_UNUSED(callResult, callResult); |
425 | } |
426 | |
427 | JSC::JSValue InjectedScript::arrayFromVector(Vector<JSC::JSValue>&& vector) |
428 | { |
429 | JSC::JSGlobalObject* globalObject = this->globalObject(); |
430 | if (!globalObject) |
431 | return JSC::jsUndefined(); |
432 | |
433 | JSC::JSLockHolder lock(globalObject); |
434 | |
435 | JSC::JSArray* array = JSC::constructEmptyArray(globalObject, nullptr); |
436 | if (!array) |
437 | return JSC::jsUndefined(); |
438 | |
439 | for (auto& item : vector) |
440 | array->putDirectIndex(globalObject, array->length(), item); |
441 | |
442 | return array; |
443 | } |
444 | |
445 | } // namespace Inspector |
446 | |
447 | |