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