LCOV - code coverage report
Current view: top level - src/inspector - injected-script.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 397 424 93.6 %
Date: 2019-02-19 Functions: 49 54 90.7 %

          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

Generated by: LCOV version 1.10