Line data Source code
1 : /*
2 : * Copyright (C) 2012 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 "src/inspector/injected-script.h"
32 :
33 : #include <cmath>
34 : #include <unordered_set>
35 :
36 : #include "src/inspector/custom-preview.h"
37 : #include "src/inspector/inspected-context.h"
38 : #include "src/inspector/protocol/Protocol.h"
39 : #include "src/inspector/remote-object-id.h"
40 : #include "src/inspector/string-util.h"
41 : #include "src/inspector/v8-console.h"
42 : #include "src/inspector/v8-inspector-impl.h"
43 : #include "src/inspector/v8-inspector-session-impl.h"
44 : #include "src/inspector/v8-stack-trace-impl.h"
45 : #include "src/inspector/v8-value-utils.h"
46 : #include "src/inspector/value-mirror.h"
47 :
48 : #include "include/v8-inspector.h"
49 :
50 : namespace v8_inspector {
51 :
52 : namespace {
53 : static const char kGlobalHandleLabel[] = "DevTools console";
54 30 : static bool isResolvableNumberLike(String16 query) {
55 180 : return query == "Infinity" || query == "-Infinity" || query == "NaN";
56 : }
57 : } // namespace
58 :
59 : using protocol::Array;
60 : using protocol::Runtime::PropertyDescriptor;
61 : using protocol::Runtime::InternalPropertyDescriptor;
62 : using protocol::Runtime::RemoteObject;
63 : using protocol::Maybe;
64 :
65 1300 : class InjectedScript::ProtocolPromiseHandler {
66 : public:
67 1300 : static bool add(V8InspectorSessionImpl* session,
68 : v8::Local<v8::Context> context, v8::Local<v8::Value> value,
69 : int executionContextId, const String16& objectGroup,
70 : WrapMode wrapMode, EvaluateCallback* callback) {
71 : v8::Local<v8::Promise::Resolver> resolver;
72 1300 : if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) {
73 0 : callback->sendFailure(Response::InternalError());
74 0 : return false;
75 : }
76 1300 : if (!resolver->Resolve(context, value).FromMaybe(false)) {
77 0 : callback->sendFailure(Response::InternalError());
78 0 : return false;
79 : }
80 :
81 650 : v8::Local<v8::Promise> promise = resolver->GetPromise();
82 650 : V8InspectorImpl* inspector = session->inspector();
83 : ProtocolPromiseHandler* handler = new ProtocolPromiseHandler(
84 650 : session, executionContextId, objectGroup, wrapMode, callback);
85 : v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate());
86 : v8::Local<v8::Function> thenCallbackFunction =
87 : v8::Function::New(context, thenCallback, wrapper, 0,
88 : v8::ConstructorBehavior::kThrow)
89 1300 : .ToLocalChecked();
90 1300 : if (promise->Then(context, thenCallbackFunction).IsEmpty()) {
91 0 : callback->sendFailure(Response::InternalError());
92 0 : return false;
93 : }
94 : v8::Local<v8::Function> catchCallbackFunction =
95 : v8::Function::New(context, catchCallback, wrapper, 0,
96 : v8::ConstructorBehavior::kThrow)
97 1300 : .ToLocalChecked();
98 1300 : if (promise->Catch(context, catchCallbackFunction).IsEmpty()) {
99 0 : callback->sendFailure(Response::InternalError());
100 0 : return false;
101 : }
102 : return true;
103 : }
104 :
105 : private:
106 1190 : static void thenCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
107 : ProtocolPromiseHandler* handler = static_cast<ProtocolPromiseHandler*>(
108 595 : info.Data().As<v8::External>()->Value());
109 : DCHECK(handler);
110 : v8::Local<v8::Value> value =
111 : info.Length() > 0
112 : ? info[0]
113 1190 : : v8::Local<v8::Value>::Cast(v8::Undefined(info.GetIsolate()));
114 595 : handler->thenCallback(value);
115 595 : delete handler;
116 595 : }
117 :
118 90 : static void catchCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
119 : ProtocolPromiseHandler* handler = static_cast<ProtocolPromiseHandler*>(
120 45 : info.Data().As<v8::External>()->Value());
121 : DCHECK(handler);
122 : v8::Local<v8::Value> value =
123 : info.Length() > 0
124 : ? info[0]
125 90 : : v8::Local<v8::Value>::Cast(v8::Undefined(info.GetIsolate()));
126 45 : handler->catchCallback(value);
127 45 : delete handler;
128 45 : }
129 :
130 1950 : ProtocolPromiseHandler(V8InspectorSessionImpl* session,
131 : int executionContextId, const String16& objectGroup,
132 : WrapMode wrapMode, EvaluateCallback* callback)
133 : : m_inspector(session->inspector()),
134 : m_sessionId(session->sessionId()),
135 : m_contextGroupId(session->contextGroupId()),
136 : m_executionContextId(executionContextId),
137 : m_objectGroup(objectGroup),
138 : m_wrapMode(wrapMode),
139 : m_callback(std::move(callback)),
140 : m_wrapper(m_inspector->isolate(),
141 2600 : v8::External::New(m_inspector->isolate(), this)) {
142 : m_wrapper.SetWeak(this, cleanup, v8::WeakCallbackType::kParameter);
143 650 : }
144 :
145 20 : static void cleanup(
146 40 : const v8::WeakCallbackInfo<ProtocolPromiseHandler>& data) {
147 20 : if (!data.GetParameter()->m_wrapper.IsEmpty()) {
148 : data.GetParameter()->m_wrapper.Reset();
149 : data.SetSecondPassCallback(cleanup);
150 : } else {
151 10 : data.GetParameter()->sendPromiseCollected();
152 10 : delete data.GetParameter();
153 : }
154 20 : }
155 :
156 595 : void thenCallback(v8::Local<v8::Value> result) {
157 : V8InspectorSessionImpl* session =
158 595 : m_inspector->sessionById(m_contextGroupId, m_sessionId);
159 600 : if (!session) return;
160 595 : InjectedScript::ContextScope scope(session, m_executionContextId);
161 595 : Response response = scope.initialize();
162 595 : if (!response.isSuccess()) return;
163 1190 : if (m_objectGroup == "console") {
164 5 : scope.injectedScript()->setLastEvaluationResult(result);
165 : }
166 : std::unique_ptr<EvaluateCallback> callback =
167 595 : scope.injectedScript()->takeEvaluateCallback(m_callback);
168 595 : if (!callback) return;
169 595 : std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
170 1190 : response = scope.injectedScript()->wrapObject(result, m_objectGroup,
171 : m_wrapMode, &wrappedValue);
172 595 : if (!response.isSuccess()) {
173 5 : callback->sendFailure(response);
174 : return;
175 : }
176 : callback->sendSuccess(std::move(wrappedValue),
177 2360 : Maybe<protocol::Runtime::ExceptionDetails>());
178 : }
179 :
180 45 : void catchCallback(v8::Local<v8::Value> result) {
181 45 : V8InspectorSessionImpl* session =
182 45 : m_inspector->sessionById(m_contextGroupId, m_sessionId);
183 45 : if (!session) return;
184 45 : InjectedScript::ContextScope scope(session, m_executionContextId);
185 45 : Response response = scope.initialize();
186 45 : if (!response.isSuccess()) return;
187 : std::unique_ptr<EvaluateCallback> callback =
188 45 : scope.injectedScript()->takeEvaluateCallback(m_callback);
189 45 : if (!callback) return;
190 45 : std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
191 90 : response = scope.injectedScript()->wrapObject(result, m_objectGroup,
192 : m_wrapMode, &wrappedValue);
193 45 : if (!response.isSuccess()) {
194 0 : callback->sendFailure(response);
195 : return;
196 : }
197 : String16 message;
198 : std::unique_ptr<V8StackTraceImpl> stack;
199 45 : v8::Isolate* isolate = session->inspector()->isolate();
200 45 : if (result->IsNativeError()) {
201 60 : message = " " + toProtocolString(
202 : isolate,
203 15 : result->ToDetailString(isolate->GetCurrentContext())
204 : .ToLocalChecked());
205 : v8::Local<v8::StackTrace> stackTrace = v8::debug::GetDetailedStackTrace(
206 15 : isolate, v8::Local<v8::Object>::Cast(result));
207 15 : if (!stackTrace.IsEmpty()) {
208 30 : stack = m_inspector->debugger()->createStackTrace(stackTrace);
209 : }
210 : }
211 45 : if (!stack) {
212 105 : stack = m_inspector->debugger()->captureStackTrace(true);
213 : }
214 : std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails =
215 : protocol::Runtime::ExceptionDetails::create()
216 135 : .setExceptionId(m_inspector->nextExceptionId())
217 90 : .setText("Uncaught (in promise)" + message)
218 10 : .setLineNumber(stack && !stack->isEmpty() ? stack->topLineNumber()
219 55 : : 0)
220 : .setColumnNumber(
221 45 : stack && !stack->isEmpty() ? stack->topColumnNumber() : 0)
222 90 : .setException(wrappedValue->clone())
223 : .build();
224 45 : if (stack)
225 : exceptionDetails->setStackTrace(
226 30 : stack->buildInspectorObjectImpl(m_inspector->debugger()));
227 45 : if (stack && !stack->isEmpty())
228 20 : exceptionDetails->setScriptId(toString16(stack->topScriptId()));
229 180 : callback->sendSuccess(std::move(wrappedValue), std::move(exceptionDetails));
230 : }
231 :
232 10 : void sendPromiseCollected() {
233 : V8InspectorSessionImpl* session =
234 10 : m_inspector->sessionById(m_contextGroupId, m_sessionId);
235 15 : if (!session) return;
236 10 : InjectedScript::ContextScope scope(session, m_executionContextId);
237 10 : Response response = scope.initialize();
238 10 : if (!response.isSuccess()) return;
239 : std::unique_ptr<EvaluateCallback> callback =
240 5 : scope.injectedScript()->takeEvaluateCallback(m_callback);
241 5 : if (!callback) return;
242 15 : callback->sendFailure(Response::Error("Promise was collected"));
243 : }
244 :
245 : V8InspectorImpl* m_inspector;
246 : int m_sessionId;
247 : int m_contextGroupId;
248 : int m_executionContextId;
249 : String16 m_objectGroup;
250 : WrapMode m_wrapMode;
251 : EvaluateCallback* m_callback;
252 : v8::Global<v8::External> m_wrapper;
253 : };
254 :
255 3311 : InjectedScript::InjectedScript(InspectedContext* context, int sessionId)
256 19866 : : m_context(context), m_sessionId(sessionId) {}
257 :
258 6622 : InjectedScript::~InjectedScript() { discardEvaluateCallbacks(); }
259 :
260 : namespace {
261 68298 : class PropertyAccumulator : public ValueMirror::PropertyAccumulator {
262 : public:
263 : explicit PropertyAccumulator(std::vector<PropertyMirror>* mirrors)
264 68298 : : m_mirrors(mirrors) {}
265 2506694 : bool Add(PropertyMirror mirror) override {
266 2506694 : m_mirrors->push_back(std::move(mirror));
267 2506694 : return true;
268 : }
269 :
270 : private:
271 : std::vector<PropertyMirror>* m_mirrors;
272 : };
273 : } // anonymous namespace
274 :
275 68298 : Response InjectedScript::getProperties(
276 : v8::Local<v8::Object> object, const String16& groupName, bool ownProperties,
277 : bool accessorPropertiesOnly, WrapMode wrapMode,
278 : std::unique_ptr<Array<PropertyDescriptor>>* properties,
279 : Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
280 68298 : v8::HandleScope handles(m_context->isolate());
281 68298 : v8::Local<v8::Context> context = m_context->context();
282 68298 : v8::Isolate* isolate = m_context->isolate();
283 68298 : int sessionId = m_sessionId;
284 136596 : v8::TryCatch tryCatch(isolate);
285 :
286 : *properties = Array<PropertyDescriptor>::create();
287 68298 : std::vector<PropertyMirror> mirrors;
288 : PropertyAccumulator accumulator(&mirrors);
289 68298 : if (!ValueMirror::getProperties(context, object, ownProperties,
290 68298 : accessorPropertiesOnly, &accumulator)) {
291 : return createExceptionDetails(tryCatch, groupName, wrapMode,
292 0 : exceptionDetails);
293 : }
294 2643290 : for (const PropertyMirror& mirror : mirrors) {
295 : std::unique_ptr<PropertyDescriptor> descriptor =
296 : PropertyDescriptor::create()
297 2506694 : .setName(mirror.name)
298 2506694 : .setConfigurable(mirror.configurable)
299 2506694 : .setEnumerable(mirror.enumerable)
300 2506694 : .setIsOwn(mirror.isOwn)
301 : .build();
302 : Response response;
303 2506694 : std::unique_ptr<RemoteObject> remoteObject;
304 2506694 : if (mirror.value) {
305 5012718 : response = wrapObjectMirror(*mirror.value, groupName, wrapMode,
306 : v8::MaybeLocal<v8::Value>(),
307 : kMaxCustomPreviewDepth, &remoteObject);
308 2506359 : if (!response.isSuccess()) return response;
309 : descriptor->setValue(std::move(remoteObject));
310 2506359 : descriptor->setWritable(mirror.writable);
311 : }
312 2506694 : if (mirror.getter) {
313 670 : response =
314 335 : mirror.getter->buildRemoteObject(context, wrapMode, &remoteObject);
315 335 : if (!response.isSuccess()) return response;
316 670 : response =
317 335 : bindRemoteObjectIfNeeded(sessionId, context, mirror.getter->v8Value(),
318 : groupName, remoteObject.get());
319 335 : if (!response.isSuccess()) return response;
320 : descriptor->setGet(std::move(remoteObject));
321 : }
322 2506694 : if (mirror.setter) {
323 660 : response =
324 330 : mirror.setter->buildRemoteObject(context, wrapMode, &remoteObject);
325 330 : if (!response.isSuccess()) return response;
326 660 : response =
327 330 : bindRemoteObjectIfNeeded(sessionId, context, mirror.setter->v8Value(),
328 : groupName, remoteObject.get());
329 330 : if (!response.isSuccess()) return response;
330 : descriptor->setSet(std::move(remoteObject));
331 : }
332 2506694 : if (mirror.symbol) {
333 36770 : response =
334 18385 : mirror.symbol->buildRemoteObject(context, wrapMode, &remoteObject);
335 18385 : if (!response.isSuccess()) return response;
336 36770 : response =
337 18385 : bindRemoteObjectIfNeeded(sessionId, context, mirror.symbol->v8Value(),
338 : groupName, remoteObject.get());
339 18385 : if (!response.isSuccess()) return response;
340 : descriptor->setSymbol(std::move(remoteObject));
341 : }
342 2506694 : if (mirror.exception) {
343 0 : response =
344 0 : mirror.exception->buildRemoteObject(context, wrapMode, &remoteObject);
345 0 : if (!response.isSuccess()) return response;
346 0 : response = bindRemoteObjectIfNeeded(sessionId, context,
347 0 : mirror.exception->v8Value(),
348 : groupName, remoteObject.get());
349 0 : if (!response.isSuccess()) return response;
350 : descriptor->setValue(std::move(remoteObject));
351 : descriptor->setWasThrown(true);
352 : }
353 2506694 : (*properties)->addItem(std::move(descriptor));
354 : }
355 136596 : return Response::OK();
356 : }
357 :
358 68293 : Response InjectedScript::getInternalProperties(
359 : v8::Local<v8::Value> value, const String16& groupName,
360 : std::unique_ptr<protocol::Array<InternalPropertyDescriptor>>* result) {
361 : *result = protocol::Array<InternalPropertyDescriptor>::create();
362 68293 : v8::Local<v8::Context> context = m_context->context();
363 68293 : int sessionId = m_sessionId;
364 : std::vector<InternalPropertyMirror> wrappers;
365 68293 : if (value->IsObject()) {
366 : ValueMirror::getInternalProperties(m_context->context(),
367 68293 : value.As<v8::Object>(), &wrappers);
368 : }
369 139763 : for (size_t i = 0; i < wrappers.size(); ++i) {
370 1059 : std::unique_ptr<RemoteObject> remoteObject;
371 : Response response = wrappers[i].value->buildRemoteObject(
372 1059 : m_context->context(), WrapMode::kNoPreview, &remoteObject);
373 1059 : if (!response.isSuccess()) return response;
374 2118 : response = bindRemoteObjectIfNeeded(sessionId, context,
375 2118 : wrappers[i].value->v8Value(), groupName,
376 : remoteObject.get());
377 1059 : if (!response.isSuccess()) return response;
378 : (*result)->addItem(InternalPropertyDescriptor::create()
379 2118 : .setName(wrappers[i].name)
380 : .setValue(std::move(remoteObject))
381 1059 : .build());
382 : }
383 68293 : return Response::OK();
384 : }
385 :
386 5 : void InjectedScript::releaseObject(const String16& objectId) {
387 : std::unique_ptr<protocol::Value> parsedObjectId =
388 5 : protocol::StringUtil::parseJSON(objectId);
389 5 : if (!parsedObjectId) return;
390 : protocol::DictionaryValue* object =
391 : protocol::DictionaryValue::cast(parsedObjectId.get());
392 5 : if (!object) return;
393 5 : int boundId = 0;
394 10 : if (!object->getInteger("id", &boundId)) return;
395 5 : unbindObject(boundId);
396 : }
397 :
398 530120 : Response InjectedScript::wrapObject(
399 : v8::Local<v8::Value> value, const String16& groupName, WrapMode wrapMode,
400 : std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
401 : return wrapObject(value, groupName, wrapMode, v8::MaybeLocal<v8::Value>(),
402 552229 : kMaxCustomPreviewDepth, result);
403 : }
404 :
405 552259 : Response InjectedScript::wrapObject(
406 : v8::Local<v8::Value> value, const String16& groupName, WrapMode wrapMode,
407 : v8::MaybeLocal<v8::Value> customPreviewConfig, int maxCustomPreviewDepth,
408 : std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
409 552259 : v8::Local<v8::Context> context = m_context->context();
410 : v8::Context::Scope contextScope(context);
411 552259 : std::unique_ptr<ValueMirror> mirror = ValueMirror::create(context, value);
412 552259 : if (!mirror) return Response::InternalError();
413 : return wrapObjectMirror(*mirror, groupName, wrapMode, customPreviewConfig,
414 552259 : maxCustomPreviewDepth, result);
415 : }
416 :
417 3058618 : Response InjectedScript::wrapObjectMirror(
418 : const ValueMirror& mirror, const String16& groupName, WrapMode wrapMode,
419 : v8::MaybeLocal<v8::Value> customPreviewConfig, int maxCustomPreviewDepth,
420 : std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
421 3058618 : int customPreviewEnabled = m_customPreviewEnabled;
422 3058618 : int sessionId = m_sessionId;
423 3058618 : v8::Local<v8::Context> context = m_context->context();
424 : v8::Context::Scope contextScope(context);
425 3058618 : Response response = mirror.buildRemoteObject(context, wrapMode, result);
426 3058618 : if (!response.isSuccess()) return response;
427 3058593 : v8::Local<v8::Value> value = mirror.v8Value();
428 6117186 : response = bindRemoteObjectIfNeeded(sessionId, context, value, groupName,
429 : result->get());
430 3058593 : if (!response.isSuccess()) return response;
431 3058593 : if (customPreviewEnabled && value->IsObject()) {
432 170 : std::unique_ptr<protocol::Runtime::CustomPreview> customPreview;
433 : generateCustomPreview(sessionId, groupName, context, value.As<v8::Object>(),
434 : customPreviewConfig, maxCustomPreviewDepth,
435 170 : &customPreview);
436 170 : if (customPreview) (*result)->setCustomPreview(std::move(customPreview));
437 : }
438 3058593 : return Response::OK();
439 : }
440 :
441 150 : std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
442 : v8::Local<v8::Object> table, v8::MaybeLocal<v8::Array> maybeColumns) {
443 : using protocol::Runtime::RemoteObject;
444 : using protocol::Runtime::ObjectPreview;
445 : using protocol::Runtime::PropertyPreview;
446 : using protocol::Array;
447 :
448 150 : v8::Isolate* isolate = m_context->isolate();
449 150 : v8::HandleScope handles(isolate);
450 150 : v8::Local<v8::Context> context = m_context->context();
451 :
452 150 : std::unique_ptr<RemoteObject> remoteObject;
453 : Response response =
454 300 : wrapObject(table, "console", WrapMode::kNoPreview, &remoteObject);
455 150 : if (!remoteObject || !response.isSuccess()) return nullptr;
456 :
457 150 : auto mirror = ValueMirror::create(context, table);
458 150 : std::unique_ptr<ObjectPreview> preview;
459 150 : int limit = 1000;
460 : mirror->buildObjectPreview(context, true /* generatePreviewForTable */,
461 150 : &limit, &limit, &preview);
462 150 : if (!preview) return nullptr;
463 :
464 : Array<PropertyPreview>* columns = preview->getProperties();
465 145 : std::unordered_set<String16> selectedColumns;
466 : v8::Local<v8::Array> v8Columns;
467 145 : if (maybeColumns.ToLocal(&v8Columns)) {
468 15 : for (uint32_t i = 0; i < v8Columns->Length(); ++i) {
469 : v8::Local<v8::Value> column;
470 45 : if (v8Columns->Get(context, i).ToLocal(&column) && column->IsString()) {
471 : selectedColumns.insert(
472 30 : toProtocolString(isolate, column.As<v8::String>()));
473 : }
474 : }
475 : }
476 145 : if (!selectedColumns.empty()) {
477 60 : for (size_t i = 0; i < columns->length(); ++i) {
478 : ObjectPreview* columnPreview = columns->get(i)->getValuePreview(nullptr);
479 25 : if (!columnPreview) continue;
480 :
481 : std::unique_ptr<Array<PropertyPreview>> filtered =
482 : Array<PropertyPreview>::create();
483 : Array<PropertyPreview>* columns = columnPreview->getProperties();
484 150 : for (size_t j = 0; j < columns->length(); ++j) {
485 : PropertyPreview* property = columns->get(j);
486 50 : if (selectedColumns.find(property->getName()) !=
487 : selectedColumns.end()) {
488 50 : filtered->addItem(property->clone());
489 : }
490 : }
491 : columnPreview->setProperties(std::move(filtered));
492 : }
493 : }
494 : remoteObject->setPreview(std::move(preview));
495 150 : return remoteObject;
496 : }
497 :
498 650 : void InjectedScript::addPromiseCallback(
499 : V8InspectorSessionImpl* session, v8::MaybeLocal<v8::Value> value,
500 : const String16& objectGroup, WrapMode wrapMode,
501 : std::unique_ptr<EvaluateCallback> callback) {
502 650 : if (value.IsEmpty()) {
503 0 : callback->sendFailure(Response::InternalError());
504 650 : return;
505 : }
506 : v8::MicrotasksScope microtasksScope(m_context->isolate(),
507 1300 : v8::MicrotasksScope::kRunMicrotasks);
508 650 : if (ProtocolPromiseHandler::add(
509 : session, m_context->context(), value.ToLocalChecked(),
510 1300 : m_context->contextId(), objectGroup, wrapMode, callback.get())) {
511 1300 : m_evaluateCallbacks.insert(callback.release());
512 650 : }
513 : }
514 :
515 3311 : void InjectedScript::discardEvaluateCallbacks() {
516 6627 : for (auto& callback : m_evaluateCallbacks) {
517 15 : callback->sendFailure(Response::Error("Execution context was destroyed."));
518 5 : delete callback;
519 : }
520 : m_evaluateCallbacks.clear();
521 3311 : }
522 :
523 645 : std::unique_ptr<EvaluateCallback> InjectedScript::takeEvaluateCallback(
524 : EvaluateCallback* callback) {
525 : auto it = m_evaluateCallbacks.find(callback);
526 645 : if (it == m_evaluateCallbacks.end()) return nullptr;
527 645 : std::unique_ptr<EvaluateCallback> value(*it);
528 : m_evaluateCallbacks.erase(it);
529 : return value;
530 : }
531 :
532 70476 : Response InjectedScript::findObject(const RemoteObjectId& objectId,
533 : v8::Local<v8::Value>* outObject) const {
534 140952 : auto it = m_idToWrappedObject.find(objectId.id());
535 70476 : if (it == m_idToWrappedObject.end())
536 0 : return Response::Error("Could not find object with given id");
537 140952 : *outObject = it->second.Get(m_context->isolate());
538 70476 : return Response::OK();
539 : }
540 :
541 70381 : String16 InjectedScript::objectGroupName(const RemoteObjectId& objectId) const {
542 70381 : if (objectId.id() <= 0) return String16();
543 140762 : auto it = m_idToObjectGroupName.find(objectId.id());
544 72683 : return it != m_idToObjectGroupName.end() ? it->second : String16();
545 : }
546 :
547 46692 : void InjectedScript::releaseObjectGroup(const String16& objectGroup) {
548 93384 : if (objectGroup == "console") m_lastEvaluationResult.Reset();
549 46692 : if (objectGroup.isEmpty()) return;
550 : auto it = m_nameToObjectGroup.find(objectGroup);
551 46692 : if (it == m_nameToObjectGroup.end()) return;
552 2171668 : for (int id : it->second) unbindObject(id);
553 : m_nameToObjectGroup.erase(it);
554 : }
555 :
556 332 : void InjectedScript::setCustomObjectFormatterEnabled(bool enabled) {
557 332 : m_customPreviewEnabled = enabled;
558 332 : }
559 :
560 85 : v8::Local<v8::Value> InjectedScript::lastEvaluationResult() const {
561 85 : if (m_lastEvaluationResult.IsEmpty())
562 20 : return v8::Undefined(m_context->isolate());
563 75 : return m_lastEvaluationResult.Get(m_context->isolate());
564 : }
565 :
566 5 : void InjectedScript::setLastEvaluationResult(v8::Local<v8::Value> result) {
567 5 : m_lastEvaluationResult.Reset(m_context->isolate(), result);
568 : m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel);
569 5 : }
570 :
571 366 : Response InjectedScript::resolveCallArgument(
572 : protocol::Runtime::CallArgument* callArgument,
573 : v8::Local<v8::Value>* result) {
574 366 : if (callArgument->hasObjectId()) {
575 95 : std::unique_ptr<RemoteObjectId> remoteObjectId;
576 : Response response =
577 285 : RemoteObjectId::parse(callArgument->getObjectId(""), &remoteObjectId);
578 95 : if (!response.isSuccess()) return response;
579 361 : if (remoteObjectId->contextId() != m_context->contextId())
580 : return Response::Error(
581 : "Argument should belong to the same JavaScript world as target "
582 0 : "object");
583 95 : return findObject(*remoteObjectId, result);
584 : }
585 306 : if (callArgument->hasValue() || callArgument->hasUnserializableValue()) {
586 : String16 value;
587 266 : if (callArgument->hasValue()) {
588 1416 : value = "(" + callArgument->getValue(nullptr)->toJSONString() + ")";
589 : } else {
590 60 : String16 unserializableValue = callArgument->getUnserializableValue("");
591 : // Protect against potential identifier resolution for NaN and Infinity.
592 60 : if (isResolvableNumberLike(unserializableValue))
593 80 : value = "Number(\"" + unserializableValue + "\")";
594 : else
595 : value = unserializableValue;
596 : }
597 266 : if (!m_context->inspector()
598 : ->compileAndRunInternalScript(
599 266 : m_context->context(), toV8String(m_context->isolate(), value))
600 266 : .ToLocal(result)) {
601 0 : return Response::Error("Couldn't parse value object in call argument");
602 : }
603 266 : return Response::OK();
604 : }
605 10 : *result = v8::Undefined(m_context->isolate());
606 5 : return Response::OK();
607 : }
608 :
609 1567 : Response InjectedScript::createExceptionDetails(
610 : const v8::TryCatch& tryCatch, const String16& objectGroup,
611 : WrapMode wrapMode, Maybe<protocol::Runtime::ExceptionDetails>* result) {
612 1567 : if (!tryCatch.HasCaught()) return Response::InternalError();
613 1567 : v8::Local<v8::Message> message = tryCatch.Message();
614 1567 : v8::Local<v8::Value> exception = tryCatch.Exception();
615 : String16 messageText =
616 : message.IsEmpty()
617 : ? String16()
618 4731 : : toProtocolString(m_context->isolate(), message->Get());
619 : std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails =
620 : protocol::Runtime::ExceptionDetails::create()
621 4701 : .setExceptionId(m_context->inspector()->nextExceptionId())
622 4701 : .setText(exception.IsEmpty() ? messageText : String16("Uncaught"))
623 : .setLineNumber(
624 : message.IsEmpty()
625 : ? 0
626 3134 : : message->GetLineNumber(m_context->context()).FromMaybe(1) -
627 3134 : 1)
628 : .setColumnNumber(
629 : message.IsEmpty()
630 : ? 0
631 3134 : : message->GetStartColumn(m_context->context()).FromMaybe(0))
632 : .build();
633 1567 : if (!message.IsEmpty()) {
634 : exceptionDetails->setScriptId(String16::fromInteger(
635 3134 : static_cast<int>(message->GetScriptOrigin().ScriptID()->Value())));
636 1567 : v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace();
637 1567 : if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0)
638 : exceptionDetails->setStackTrace(
639 : m_context->inspector()
640 : ->debugger()
641 : ->createStackTrace(stackTrace)
642 150 : ->buildInspectorObjectImpl(m_context->inspector()->debugger()));
643 : }
644 1567 : if (!exception.IsEmpty()) {
645 1567 : std::unique_ptr<protocol::Runtime::RemoteObject> wrapped;
646 : Response response =
647 : wrapObject(exception, objectGroup,
648 1567 : exception->IsNativeError() ? WrapMode::kNoPreview
649 : : WrapMode::kWithPreview,
650 1567 : &wrapped);
651 1567 : if (!response.isSuccess()) return response;
652 : exceptionDetails->setException(std::move(wrapped));
653 : }
654 : *result = std::move(exceptionDetails);
655 1567 : return Response::OK();
656 : }
657 :
658 19808 : Response InjectedScript::wrapEvaluateResult(
659 : v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch& tryCatch,
660 : const String16& objectGroup, WrapMode wrapMode,
661 : std::unique_ptr<protocol::Runtime::RemoteObject>* result,
662 : Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
663 : v8::Local<v8::Value> resultValue;
664 19808 : if (!tryCatch.HasCaught()) {
665 18210 : if (!maybeResultValue.ToLocal(&resultValue))
666 20 : return Response::InternalError();
667 : Response response = wrapObject(resultValue, objectGroup, wrapMode, result);
668 18210 : if (!response.isSuccess()) return response;
669 36380 : if (objectGroup == "console") {
670 175 : m_lastEvaluationResult.Reset(m_context->isolate(), resultValue);
671 : m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel);
672 : }
673 : } else {
674 1598 : if (tryCatch.HasTerminated() || !tryCatch.CanContinue()) {
675 112 : return Response::Error("Execution was terminated");
676 : }
677 1542 : v8::Local<v8::Value> exception = tryCatch.Exception();
678 : Response response =
679 : wrapObject(exception, objectGroup,
680 1542 : exception->IsNativeError() ? WrapMode::kNoPreview
681 : : WrapMode::kWithPreview,
682 1542 : result);
683 1542 : if (!response.isSuccess()) return response;
684 : // We send exception in result for compatibility reasons, even though it's
685 : // accessible through exceptionDetails.exception.
686 3084 : response = createExceptionDetails(tryCatch, objectGroup, wrapMode,
687 : exceptionDetails);
688 1542 : if (!response.isSuccess()) return response;
689 : }
690 19732 : return Response::OK();
691 : }
692 :
693 425 : v8::Local<v8::Object> InjectedScript::commandLineAPI() {
694 425 : if (m_commandLineAPI.IsEmpty()) {
695 : m_commandLineAPI.Reset(
696 : m_context->isolate(),
697 : m_context->inspector()->console()->createCommandLineAPI(
698 60 : m_context->context(), m_sessionId));
699 : m_commandLineAPI.AnnotateStrongRetainer(kGlobalHandleLabel);
700 : }
701 850 : return m_commandLineAPI.Get(m_context->isolate());
702 : }
703 :
704 360528 : InjectedScript::Scope::Scope(V8InspectorSessionImpl* session)
705 : : m_inspector(session->inspector()),
706 : m_injectedScript(nullptr),
707 : m_handleScope(m_inspector->isolate()),
708 : m_tryCatch(m_inspector->isolate()),
709 : m_ignoreExceptionsAndMuteConsole(false),
710 : m_previousPauseOnExceptionsState(v8::debug::NoBreakOnException),
711 : m_userGesture(false),
712 : m_allowEval(false),
713 : m_contextGroupId(session->contextGroupId()),
714 450660 : m_sessionId(session->sessionId()) {}
715 :
716 111216 : Response InjectedScript::Scope::initialize() {
717 111216 : cleanup();
718 : V8InspectorSessionImpl* session =
719 111216 : m_inspector->sessionById(m_contextGroupId, m_sessionId);
720 111216 : if (!session) return Response::InternalError();
721 111211 : Response response = findInjectedScript(session);
722 111211 : if (!response.isSuccess()) return response;
723 111182 : m_context = m_injectedScript->context()->context();
724 111182 : m_context->Enter();
725 111212 : if (m_allowEval) m_context->AllowCodeGenerationFromStrings(true);
726 111182 : return Response::OK();
727 : }
728 :
729 425 : void InjectedScript::Scope::installCommandLineAPI() {
730 : DCHECK(m_injectedScript && !m_context.IsEmpty() &&
731 : !m_commandLineAPIScope.get());
732 : m_commandLineAPIScope.reset(new V8Console::CommandLineAPIScope(
733 1275 : m_context, m_injectedScript->commandLineAPI(), m_context->Global()));
734 425 : }
735 :
736 68313 : void InjectedScript::Scope::ignoreExceptionsAndMuteConsole() {
737 : DCHECK(!m_ignoreExceptionsAndMuteConsole);
738 68313 : m_ignoreExceptionsAndMuteConsole = true;
739 68313 : m_inspector->client()->muteMetrics(m_contextGroupId);
740 68313 : m_inspector->muteExceptions(m_contextGroupId);
741 : m_previousPauseOnExceptionsState =
742 68313 : setPauseOnExceptionsState(v8::debug::NoBreakOnException);
743 68313 : }
744 :
745 136626 : v8::debug::ExceptionBreakState InjectedScript::Scope::setPauseOnExceptionsState(
746 : v8::debug::ExceptionBreakState newState) {
747 273252 : if (!m_inspector->debugger()->enabled()) return newState;
748 : v8::debug::ExceptionBreakState presentState =
749 271652 : m_inspector->debugger()->getPauseOnExceptionsState();
750 135826 : if (presentState != newState)
751 708 : m_inspector->debugger()->setPauseOnExceptionsState(newState);
752 135826 : return presentState;
753 : }
754 :
755 0 : void InjectedScript::Scope::pretendUserGesture() {
756 : DCHECK(!m_userGesture);
757 0 : m_userGesture = true;
758 0 : m_inspector->client()->beginUserGesture();
759 0 : }
760 :
761 9145 : void InjectedScript::Scope::allowCodeGenerationFromStrings() {
762 : DCHECK(!m_allowEval);
763 18290 : if (m_context->IsCodeGenerationFromStringsAllowed()) return;
764 25 : m_allowEval = true;
765 25 : m_context->AllowCodeGenerationFromStrings(true);
766 : }
767 :
768 201348 : void InjectedScript::Scope::cleanup() {
769 : m_commandLineAPIScope.reset();
770 201348 : if (!m_context.IsEmpty()) {
771 111182 : if (m_allowEval) m_context->AllowCodeGenerationFromStrings(false);
772 111182 : m_context->Exit();
773 : m_context.Clear();
774 : }
775 201348 : }
776 :
777 180264 : InjectedScript::Scope::~Scope() {
778 90132 : if (m_ignoreExceptionsAndMuteConsole) {
779 68313 : setPauseOnExceptionsState(m_previousPauseOnExceptionsState);
780 68313 : m_inspector->client()->unmuteMetrics(m_contextGroupId);
781 68313 : m_inspector->unmuteExceptions(m_contextGroupId);
782 : }
783 90132 : if (m_userGesture) m_inspector->client()->endUserGesture();
784 90132 : cleanup();
785 90132 : }
786 :
787 8937 : InjectedScript::ContextScope::ContextScope(V8InspectorSessionImpl* session,
788 : int executionContextId)
789 : : InjectedScript::Scope(session),
790 9587 : m_executionContextId(executionContextId) {}
791 :
792 : InjectedScript::ContextScope::~ContextScope() = default;
793 :
794 18243 : Response InjectedScript::ContextScope::findInjectedScript(
795 : V8InspectorSessionImpl* session) {
796 18243 : return session->findInjectedScript(m_executionContextId, m_injectedScript);
797 : }
798 :
799 69094 : InjectedScript::ObjectScope::ObjectScope(V8InspectorSessionImpl* session,
800 : const String16& remoteObjectId)
801 138188 : : InjectedScript::Scope(session), m_remoteObjectId(remoteObjectId) {}
802 :
803 : InjectedScript::ObjectScope::~ObjectScope() = default;
804 :
805 70381 : Response InjectedScript::ObjectScope::findInjectedScript(
806 : V8InspectorSessionImpl* session) {
807 70381 : std::unique_ptr<RemoteObjectId> remoteId;
808 70381 : Response response = RemoteObjectId::parse(m_remoteObjectId, &remoteId);
809 70381 : if (!response.isSuccess()) return response;
810 70381 : InjectedScript* injectedScript = nullptr;
811 140762 : response = session->findInjectedScript(remoteId.get(), injectedScript);
812 70381 : if (!response.isSuccess()) return response;
813 140762 : m_objectGroupName = injectedScript->objectGroupName(*remoteId);
814 211143 : response = injectedScript->findObject(*remoteId, &m_object);
815 70381 : if (!response.isSuccess()) return response;
816 70381 : m_injectedScript = injectedScript;
817 70381 : return Response::OK();
818 : }
819 :
820 11451 : InjectedScript::CallFrameScope::CallFrameScope(V8InspectorSessionImpl* session,
821 : const String16& remoteObjectId)
822 22902 : : InjectedScript::Scope(session), m_remoteCallFrameId(remoteObjectId) {}
823 :
824 : InjectedScript::CallFrameScope::~CallFrameScope() = default;
825 :
826 22587 : Response InjectedScript::CallFrameScope::findInjectedScript(
827 : V8InspectorSessionImpl* session) {
828 22587 : std::unique_ptr<RemoteCallFrameId> remoteId;
829 22587 : Response response = RemoteCallFrameId::parse(m_remoteCallFrameId, &remoteId);
830 22587 : if (!response.isSuccess()) return response;
831 22587 : m_frameOrdinal = static_cast<size_t>(remoteId->frameOrdinal());
832 22587 : return session->findInjectedScript(remoteId.get(), m_injectedScript);
833 : }
834 :
835 2747905 : String16 InjectedScript::bindObject(v8::Local<v8::Value> value,
836 : const String16& groupName) {
837 2747905 : if (m_lastBoundObjectId <= 0) m_lastBoundObjectId = 1;
838 2747905 : int id = m_lastBoundObjectId++;
839 5495810 : m_idToWrappedObject[id].Reset(m_context->isolate(), value);
840 : m_idToWrappedObject[id].AnnotateStrongRetainer(kGlobalHandleLabel);
841 2747905 : if (!groupName.isEmpty() && id > 0) {
842 : m_idToObjectGroupName[id] = groupName;
843 2734884 : m_nameToObjectGroup[groupName].push_back(id);
844 : }
845 : // TODO(dgozman): get rid of "injectedScript" notion.
846 : return String16::concat(
847 : "{\"injectedScriptId\":", String16::fromInteger(m_context->contextId()),
848 10991620 : ",\"id\":", String16::fromInteger(id), "}");
849 : }
850 :
851 : // static
852 3078702 : Response InjectedScript::bindRemoteObjectIfNeeded(
853 : int sessionId, v8::Local<v8::Context> context, v8::Local<v8::Value> value,
854 : const String16& groupName, protocol::Runtime::RemoteObject* remoteObject) {
855 3078702 : if (!remoteObject) return Response::OK();
856 3078702 : if (remoteObject->hasValue()) return Response::OK();
857 2850848 : if (remoteObject->hasUnserializableValue()) return Response::OK();
858 8444613 : if (remoteObject->getType() != RemoteObject::TypeEnum::Undefined) {
859 2747855 : v8::Isolate* isolate = context->GetIsolate();
860 : V8InspectorImpl* inspector =
861 2747855 : static_cast<V8InspectorImpl*>(v8::debug::GetInspector(isolate));
862 : InspectedContext* inspectedContext =
863 2747855 : inspector->getContext(InspectedContext::contextId(context));
864 : InjectedScript* injectedScript =
865 : inspectedContext ? inspectedContext->getInjectedScript(sessionId)
866 2747855 : : nullptr;
867 2747855 : if (!injectedScript) {
868 0 : return Response::Error("Cannot find context with specified id");
869 : }
870 5495710 : remoteObject->setObjectId(injectedScript->bindObject(value, groupName));
871 : }
872 2814871 : return Response::OK();
873 : }
874 :
875 0 : void InjectedScript::unbindObject(int id) {
876 : m_idToWrappedObject.erase(id);
877 : m_idToObjectGroupName.erase(id);
878 0 : }
879 :
880 : } // namespace v8_inspector
|