LCOV - code coverage report
Current view: top level - src/inspector - injected-script.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 360 403 89.3 %
Date: 2017-10-20 Functions: 49 57 86.0 %

          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 "src/inspector/injected-script-source.h"
      34             : #include "src/inspector/inspected-context.h"
      35             : #include "src/inspector/protocol/Protocol.h"
      36             : #include "src/inspector/remote-object-id.h"
      37             : #include "src/inspector/string-util.h"
      38             : #include "src/inspector/v8-console.h"
      39             : #include "src/inspector/v8-function-call.h"
      40             : #include "src/inspector/v8-injected-script-host.h"
      41             : #include "src/inspector/v8-inspector-impl.h"
      42             : #include "src/inspector/v8-inspector-session-impl.h"
      43             : #include "src/inspector/v8-stack-trace-impl.h"
      44             : #include "src/inspector/v8-value-utils.h"
      45             : 
      46             : #include "include/v8-inspector.h"
      47             : 
      48             : namespace v8_inspector {
      49             : 
      50             : namespace {
      51             : static const char privateKeyName[] = "v8-inspector#injectedScript";
      52             : }  // namespace
      53             : 
      54             : using protocol::Array;
      55             : using protocol::Runtime::PropertyDescriptor;
      56             : using protocol::Runtime::InternalPropertyDescriptor;
      57             : using protocol::Runtime::RemoteObject;
      58             : using protocol::Maybe;
      59             : 
      60        1040 : class InjectedScript::ProtocolPromiseHandler {
      61             :  public:
      62        1040 :   static bool add(V8InspectorSessionImpl* session,
      63             :                   v8::Local<v8::Context> context, v8::Local<v8::Value> value,
      64             :                   int executionContextId, const String16& objectGroup,
      65             :                   bool returnByValue, bool generatePreview,
      66             :                   EvaluateCallback* callback) {
      67             :     v8::Local<v8::Promise::Resolver> resolver;
      68        1040 :     if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) {
      69           0 :       callback->sendFailure(Response::InternalError());
      70           0 :       return false;
      71             :     }
      72        1040 :     if (!resolver->Resolve(context, value).FromMaybe(false)) {
      73           0 :       callback->sendFailure(Response::InternalError());
      74           0 :       return false;
      75             :     }
      76             : 
      77         520 :     v8::Local<v8::Promise> promise = resolver->GetPromise();
      78         520 :     V8InspectorImpl* inspector = session->inspector();
      79             :     ProtocolPromiseHandler* handler =
      80             :         new ProtocolPromiseHandler(session, executionContextId, objectGroup,
      81         520 :                                    returnByValue, generatePreview, callback);
      82             :     v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate());
      83             :     v8::Local<v8::Function> thenCallbackFunction =
      84             :         v8::Function::New(context, thenCallback, wrapper, 0,
      85             :                           v8::ConstructorBehavior::kThrow)
      86        1040 :             .ToLocalChecked();
      87        1040 :     if (promise->Then(context, thenCallbackFunction).IsEmpty()) {
      88           0 :       callback->sendFailure(Response::InternalError());
      89           0 :       return false;
      90             :     }
      91             :     v8::Local<v8::Function> catchCallbackFunction =
      92             :         v8::Function::New(context, catchCallback, wrapper, 0,
      93             :                           v8::ConstructorBehavior::kThrow)
      94        1040 :             .ToLocalChecked();
      95        1040 :     if (promise->Catch(context, catchCallbackFunction).IsEmpty()) {
      96           0 :       callback->sendFailure(Response::InternalError());
      97           0 :       return false;
      98             :     }
      99             :     return true;
     100             :   }
     101             : 
     102             :  private:
     103         940 :   static void thenCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
     104             :     ProtocolPromiseHandler* handler = static_cast<ProtocolPromiseHandler*>(
     105         470 :         info.Data().As<v8::External>()->Value());
     106             :     DCHECK(handler);
     107             :     v8::Local<v8::Value> value =
     108             :         info.Length() > 0
     109             :             ? info[0]
     110         940 :             : v8::Local<v8::Value>::Cast(v8::Undefined(info.GetIsolate()));
     111         470 :     handler->thenCallback(value);
     112         470 :     delete handler;
     113         470 :   }
     114             : 
     115          80 :   static void catchCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
     116             :     ProtocolPromiseHandler* handler = static_cast<ProtocolPromiseHandler*>(
     117          40 :         info.Data().As<v8::External>()->Value());
     118             :     DCHECK(handler);
     119             :     v8::Local<v8::Value> value =
     120             :         info.Length() > 0
     121             :             ? info[0]
     122          80 :             : v8::Local<v8::Value>::Cast(v8::Undefined(info.GetIsolate()));
     123          40 :     handler->catchCallback(value);
     124          40 :     delete handler;
     125          40 :   }
     126             : 
     127        1560 :   ProtocolPromiseHandler(V8InspectorSessionImpl* session,
     128             :                          int executionContextId, const String16& objectGroup,
     129             :                          bool returnByValue, bool generatePreview,
     130             :                          EvaluateCallback* callback)
     131             :       : m_inspector(session->inspector()),
     132             :         m_sessionId(session->sessionId()),
     133             :         m_contextGroupId(session->contextGroupId()),
     134             :         m_executionContextId(executionContextId),
     135             :         m_objectGroup(objectGroup),
     136             :         m_returnByValue(returnByValue),
     137             :         m_generatePreview(generatePreview),
     138             :         m_callback(std::move(callback)),
     139             :         m_wrapper(m_inspector->isolate(),
     140        1560 :                   v8::External::New(m_inspector->isolate(), this)) {
     141             :     m_wrapper.SetWeak(this, cleanup, v8::WeakCallbackType::kParameter);
     142         520 :   }
     143             : 
     144          20 :   static void cleanup(
     145          40 :       const v8::WeakCallbackInfo<ProtocolPromiseHandler>& data) {
     146          20 :     if (!data.GetParameter()->m_wrapper.IsEmpty()) {
     147             :       data.GetParameter()->m_wrapper.Reset();
     148             :       data.SetSecondPassCallback(cleanup);
     149             :     } else {
     150          10 :       data.GetParameter()->sendPromiseCollected();
     151          10 :       delete data.GetParameter();
     152             :     }
     153          20 :   }
     154             : 
     155         470 :   void thenCallback(v8::Local<v8::Value> result) {
     156             :     V8InspectorSessionImpl* session =
     157         470 :         m_inspector->sessionById(m_contextGroupId, m_sessionId);
     158         475 :     if (!session) return;
     159         470 :     InjectedScript::ContextScope scope(session, m_executionContextId);
     160         470 :     Response response = scope.initialize();
     161         470 :     if (!response.isSuccess()) return;
     162         940 :     if (m_objectGroup == "console") {
     163           5 :       scope.injectedScript()->setLastEvaluationResult(result);
     164             :     }
     165             :     std::unique_ptr<EvaluateCallback> callback =
     166         470 :         scope.injectedScript()->takeEvaluateCallback(m_callback);
     167         470 :     if (!callback) return;
     168         470 :     std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
     169         940 :     response = scope.injectedScript()->wrapObject(
     170             :         result, m_objectGroup, m_returnByValue, m_generatePreview,
     171             :         &wrappedValue);
     172         470 :     if (!response.isSuccess()) {
     173           5 :       callback->sendFailure(response);
     174             :       return;
     175             :     }
     176             :     callback->sendSuccess(std::move(wrappedValue),
     177        1860 :                           Maybe<protocol::Runtime::ExceptionDetails>());
     178             :   }
     179             : 
     180          40 :   void catchCallback(v8::Local<v8::Value> result) {
     181          40 :     V8InspectorSessionImpl* session =
     182          40 :         m_inspector->sessionById(m_contextGroupId, m_sessionId);
     183          40 :     if (!session) return;
     184          40 :     InjectedScript::ContextScope scope(session, m_executionContextId);
     185          40 :     Response response = scope.initialize();
     186          40 :     if (!response.isSuccess()) return;
     187             :     std::unique_ptr<EvaluateCallback> callback =
     188          40 :         scope.injectedScript()->takeEvaluateCallback(m_callback);
     189          40 :     if (!callback) return;
     190          40 :     std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
     191          80 :     response = scope.injectedScript()->wrapObject(
     192             :         result, m_objectGroup, m_returnByValue, m_generatePreview,
     193             :         &wrappedValue);
     194          40 :     if (!response.isSuccess()) {
     195           0 :       callback->sendFailure(response);
     196             :       return;
     197             :     }
     198          40 :     String16 message;
     199             :     std::unique_ptr<V8StackTraceImpl> stack;
     200          40 :     v8::Isolate* isolate = session->inspector()->isolate();
     201          40 :     if (result->IsNativeError()) {
     202          60 :       message = " " + toProtocolString(
     203          15 :                           result->ToDetailString(isolate->GetCurrentContext())
     204          15 :                               .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          40 :     if (!stack) {
     212          90 :       stack = m_inspector->debugger()->captureStackTrace(true);
     213             :     }
     214             :     std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails =
     215             :         protocol::Runtime::ExceptionDetails::create()
     216         120 :             .setExceptionId(m_inspector->nextExceptionId())
     217          80 :             .setText("Uncaught (in promise)" + message)
     218          25 :             .setLineNumber(stack && !stack->isEmpty() ? stack->topLineNumber()
     219          50 :                                                       : 0)
     220             :             .setColumnNumber(
     221          40 :                 stack && !stack->isEmpty() ? stack->topColumnNumber() : 0)
     222          80 :             .setException(wrappedValue->clone())
     223             :             .build();
     224          40 :     if (stack)
     225          50 :       exceptionDetails->setStackTrace(stack->buildInspectorObjectImpl());
     226          40 :     if (stack && !stack->isEmpty())
     227          20 :       exceptionDetails->setScriptId(toString16(stack->topScriptId()));
     228         160 :     callback->sendSuccess(std::move(wrappedValue), std::move(exceptionDetails));
     229             :   }
     230             : 
     231          10 :   void sendPromiseCollected() {
     232             :     V8InspectorSessionImpl* session =
     233          10 :         m_inspector->sessionById(m_contextGroupId, m_sessionId);
     234          15 :     if (!session) return;
     235          10 :     InjectedScript::ContextScope scope(session, m_executionContextId);
     236          10 :     Response response = scope.initialize();
     237          10 :     if (!response.isSuccess()) return;
     238             :     std::unique_ptr<EvaluateCallback> callback =
     239           5 :         scope.injectedScript()->takeEvaluateCallback(m_callback);
     240           5 :     if (!callback) return;
     241          15 :     callback->sendFailure(Response::Error("Promise was collected"));
     242             :   }
     243             : 
     244             :   V8InspectorImpl* m_inspector;
     245             :   int m_sessionId;
     246             :   int m_contextGroupId;
     247             :   int m_executionContextId;
     248             :   String16 m_objectGroup;
     249             :   bool m_returnByValue;
     250             :   bool m_generatePreview;
     251             :   EvaluateCallback* m_callback;
     252             :   v8::Global<v8::External> m_wrapper;
     253             : };
     254             : 
     255        2944 : std::unique_ptr<InjectedScript> InjectedScript::create(
     256       11776 :     InspectedContext* inspectedContext, int sessionId) {
     257        2944 :   v8::Isolate* isolate = inspectedContext->isolate();
     258        2944 :   v8::HandleScope handles(isolate);
     259        5888 :   v8::TryCatch tryCatch(isolate);
     260        2944 :   v8::Local<v8::Context> context = inspectedContext->context();
     261             :   v8::Context::Scope scope(context);
     262             :   v8::MicrotasksScope microtasksScope(isolate,
     263        5888 :                                       v8::MicrotasksScope::kDoNotRunMicrotasks);
     264             : 
     265             :   // Inject javascript into the context. The compiled script is supposed to
     266             :   // evaluate into
     267             :   // a single anonymous function(it's anonymous to avoid cluttering the global
     268             :   // object with
     269             :   // inspector's stuff) the function is called a few lines below with
     270             :   // InjectedScriptHost wrapper,
     271             :   // injected script id and explicit reference to the inspected global object.
     272             :   // The function is expected
     273             :   // to create and configure InjectedScript instance that is going to be used by
     274             :   // the inspector.
     275             :   StringView injectedScriptSource(
     276             :       reinterpret_cast<const uint8_t*>(InjectedScriptSource_js),
     277             :       sizeof(InjectedScriptSource_js));
     278             :   v8::Local<v8::Value> value;
     279        2944 :   if (!inspectedContext->inspector()
     280             :            ->compileAndRunInternalScript(
     281        2944 :                context, toV8String(isolate, injectedScriptSource))
     282        2944 :            .ToLocal(&value))
     283             :     return nullptr;
     284             :   DCHECK(value->IsFunction());
     285             :   v8::Local<v8::Object> scriptHostWrapper =
     286        2944 :       V8InjectedScriptHost::create(context, inspectedContext->inspector());
     287             :   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value);
     288        2944 :   v8::Local<v8::Object> windowGlobal = context->Global();
     289             :   v8::Local<v8::Value> info[] = {
     290             :       scriptHostWrapper, windowGlobal,
     291        2944 :       v8::Number::New(isolate, inspectedContext->contextId())};
     292             : 
     293             :   int contextGroupId = inspectedContext->contextGroupId();
     294             :   int contextId = inspectedContext->contextId();
     295             :   V8InspectorImpl* inspector = inspectedContext->inspector();
     296             :   v8::Local<v8::Value> injectedScriptValue;
     297        2944 :   if (!function->Call(context, windowGlobal, arraysize(info), info)
     298        2944 :            .ToLocal(&injectedScriptValue))
     299             :     return nullptr;
     300        2944 :   if (inspector->getContext(contextGroupId, contextId) != inspectedContext)
     301             :     return nullptr;
     302        2944 :   if (!injectedScriptValue->IsObject()) return nullptr;
     303             : 
     304             :   std::unique_ptr<InjectedScript> injectedScript(new InjectedScript(
     305        2944 :       inspectedContext, injectedScriptValue.As<v8::Object>(), sessionId));
     306             :   v8::Local<v8::Private> privateKey = v8::Private::ForApi(
     307             :       isolate, v8::String::NewFromUtf8(isolate, privateKeyName,
     308             :                                        v8::NewStringType::kInternalized)
     309        5888 :                    .ToLocalChecked());
     310             :   scriptHostWrapper->SetPrivate(
     311        5888 :       context, privateKey, v8::External::New(isolate, injectedScript.get()));
     312        2944 :   return injectedScript;
     313             : }
     314             : 
     315        2944 : InjectedScript::InjectedScript(InspectedContext* context,
     316             :                                v8::Local<v8::Object> object, int sessionId)
     317             :     : m_context(context),
     318             :       m_value(context->isolate(), object),
     319       20608 :       m_sessionId(sessionId) {}
     320             : 
     321        5888 : InjectedScript::~InjectedScript() { discardEvaluateCallbacks(); }
     322             : 
     323       67096 : Response InjectedScript::getProperties(
     324             :     v8::Local<v8::Object> object, const String16& groupName, bool ownProperties,
     325             :     bool accessorPropertiesOnly, bool generatePreview,
     326             :     std::unique_ptr<Array<PropertyDescriptor>>* properties,
     327             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
     328      134192 :   v8::HandleScope handles(m_context->isolate());
     329       67096 :   v8::Local<v8::Context> context = m_context->context();
     330             :   V8FunctionCall function(m_context->inspector(), m_context->context(),
     331      201288 :                           v8Value(), "getProperties");
     332       67096 :   function.appendArgument(object);
     333       67096 :   function.appendArgument(groupName);
     334       67096 :   function.appendArgument(ownProperties);
     335       67096 :   function.appendArgument(accessorPropertiesOnly);
     336       67096 :   function.appendArgument(generatePreview);
     337             : 
     338      134192 :   v8::TryCatch tryCatch(m_context->isolate());
     339       67096 :   v8::Local<v8::Value> resultValue = function.callWithoutExceptionHandling();
     340       67096 :   if (tryCatch.HasCaught()) {
     341             :     Response response = createExceptionDetails(
     342           0 :         tryCatch, groupName, generatePreview, exceptionDetails);
     343           0 :     if (!response.isSuccess()) return response;
     344             :     // FIXME: make properties optional
     345             :     *properties = Array<PropertyDescriptor>::create();
     346           0 :     return Response::OK();
     347             :   }
     348       67096 :   if (resultValue.IsEmpty()) return Response::InternalError();
     349       67096 :   std::unique_ptr<protocol::Value> protocolValue;
     350       67096 :   Response response = toProtocolValue(context, resultValue, &protocolValue);
     351       67096 :   if (!response.isSuccess()) return response;
     352      134192 :   protocol::ErrorSupport errors;
     353             :   std::unique_ptr<Array<PropertyDescriptor>> result =
     354       67096 :       Array<PropertyDescriptor>::fromValue(protocolValue.get(), &errors);
     355       67096 :   if (errors.hasErrors()) return Response::Error(errors.errors());
     356             :   *properties = std::move(result);
     357      134192 :   return Response::OK();
     358             : }
     359             : 
     360           5 : void InjectedScript::releaseObject(const String16& objectId) {
     361             :   std::unique_ptr<protocol::Value> parsedObjectId =
     362           5 :       protocol::StringUtil::parseJSON(objectId);
     363           5 :   if (!parsedObjectId) return;
     364             :   protocol::DictionaryValue* object =
     365             :       protocol::DictionaryValue::cast(parsedObjectId.get());
     366           5 :   if (!object) return;
     367           5 :   int boundId = 0;
     368          10 :   if (!object->getInteger("id", &boundId)) return;
     369           5 :   unbindObject(boundId);
     370             : }
     371             : 
     372      482802 : Response InjectedScript::wrapObject(
     373             :     v8::Local<v8::Value> value, const String16& groupName, bool forceValueType,
     374             :     bool generatePreview,
     375             :     std::unique_ptr<protocol::Runtime::RemoteObject>* result) const {
     376      482802 :   v8::HandleScope handles(m_context->isolate());
     377             :   v8::Local<v8::Value> wrappedObject;
     378      482802 :   v8::Local<v8::Context> context = m_context->context();
     379             :   Response response = wrapValue(value, groupName, forceValueType,
     380      482802 :                                 generatePreview, &wrappedObject);
     381      482802 :   if (!response.isSuccess()) return response;
     382      965408 :   protocol::ErrorSupport errors;
     383      482704 :   std::unique_ptr<protocol::Value> protocolValue;
     384      965408 :   response = toProtocolValue(context, wrappedObject, &protocolValue);
     385      482704 :   if (!response.isSuccess()) return response;
     386             : 
     387      965398 :   *result =
     388             :       protocol::Runtime::RemoteObject::fromValue(protocolValue.get(), &errors);
     389      482699 :   if (!result->get()) return Response::Error(errors.errors());
     390      965501 :   return Response::OK();
     391             : }
     392             : 
     393           0 : Response InjectedScript::wrapObjectProperty(v8::Local<v8::Object> object,
     394             :                                             v8::Local<v8::Name> key,
     395             :                                             const String16& groupName,
     396             :                                             bool forceValueType,
     397             :                                             bool generatePreview) const {
     398             :   v8::Local<v8::Value> property;
     399           0 :   v8::Local<v8::Context> context = m_context->context();
     400           0 :   if (!object->Get(context, key).ToLocal(&property))
     401           0 :     return Response::InternalError();
     402             :   v8::Local<v8::Value> wrappedProperty;
     403             :   Response response = wrapValue(property, groupName, forceValueType,
     404           0 :                                 generatePreview, &wrappedProperty);
     405           0 :   if (!response.isSuccess()) return response;
     406             :   v8::Maybe<bool> success =
     407           0 :       createDataProperty(context, object, key, wrappedProperty);
     408           0 :   if (success.IsNothing() || !success.FromJust())
     409           0 :     return Response::InternalError();
     410           0 :   return Response::OK();
     411             : }
     412             : 
     413           0 : Response InjectedScript::wrapPropertyInArray(v8::Local<v8::Array> array,
     414             :                                              v8::Local<v8::String> property,
     415             :                                              const String16& groupName,
     416             :                                              bool forceValueType,
     417             :                                              bool generatePreview) const {
     418             :   V8FunctionCall function(m_context->inspector(), m_context->context(),
     419           0 :                           v8Value(), "wrapPropertyInArray");
     420           0 :   function.appendArgument(array);
     421           0 :   function.appendArgument(property);
     422           0 :   function.appendArgument(groupName);
     423           0 :   function.appendArgument(forceValueType);
     424           0 :   function.appendArgument(generatePreview);
     425           0 :   bool hadException = false;
     426           0 :   function.call(hadException);
     427           0 :   return hadException ? Response::InternalError() : Response::OK();
     428             : }
     429             : 
     430      482802 : Response InjectedScript::wrapValue(v8::Local<v8::Value> value,
     431             :                                    const String16& groupName,
     432             :                                    bool forceValueType, bool generatePreview,
     433             :                                    v8::Local<v8::Value>* result) const {
     434             :   V8FunctionCall function(m_context->inspector(), m_context->context(),
     435      965604 :                           v8Value(), "wrapObject");
     436      482802 :   function.appendArgument(value);
     437      482802 :   function.appendArgument(groupName);
     438      482802 :   function.appendArgument(forceValueType);
     439      482802 :   function.appendArgument(generatePreview);
     440      482802 :   bool hadException = false;
     441      482802 :   *result = function.call(hadException);
     442      965506 :   if (hadException || result->IsEmpty()) return Response::InternalError();
     443      482704 :   return Response::OK();
     444             : }
     445             : 
     446         105 : std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
     447             :     v8::Local<v8::Value> table, v8::Local<v8::Value> columns) const {
     448         210 :   v8::HandleScope handles(m_context->isolate());
     449         105 :   v8::Local<v8::Context> context = m_context->context();
     450             :   V8FunctionCall function(m_context->inspector(), context, v8Value(),
     451         315 :                           "wrapTable");
     452         105 :   function.appendArgument(table);
     453         105 :   if (columns.IsEmpty())
     454         100 :     function.appendArgument(false);
     455             :   else
     456           5 :     function.appendArgument(columns);
     457         105 :   bool hadException = false;
     458         105 :   v8::Local<v8::Value> r = function.call(hadException);
     459         210 :   if (hadException || r.IsEmpty()) return nullptr;
     460         105 :   std::unique_ptr<protocol::Value> protocolValue;
     461         105 :   Response response = toProtocolValue(context, r, &protocolValue);
     462         105 :   if (!response.isSuccess()) return nullptr;
     463         210 :   protocol::ErrorSupport errors;
     464             :   return protocol::Runtime::RemoteObject::fromValue(protocolValue.get(),
     465         210 :                                                     &errors);
     466             : }
     467             : 
     468         520 : void InjectedScript::addPromiseCallback(
     469             :     V8InspectorSessionImpl* session, v8::MaybeLocal<v8::Value> value,
     470             :     const String16& objectGroup, bool returnByValue, bool generatePreview,
     471             :     std::unique_ptr<EvaluateCallback> callback) {
     472         520 :   if (value.IsEmpty()) {
     473           0 :     callback->sendFailure(Response::InternalError());
     474         520 :     return;
     475             :   }
     476             :   v8::MicrotasksScope microtasksScope(m_context->isolate(),
     477        1040 :                                       v8::MicrotasksScope::kRunMicrotasks);
     478         520 :   if (ProtocolPromiseHandler::add(
     479             :           session, m_context->context(), value.ToLocalChecked(),
     480             :           m_context->contextId(), objectGroup, returnByValue, generatePreview,
     481        1040 :           callback.get())) {
     482        1040 :     m_evaluateCallbacks.insert(callback.release());
     483         520 :   }
     484             : }
     485             : 
     486        2944 : void InjectedScript::discardEvaluateCallbacks() {
     487        5893 :   for (auto& callback : m_evaluateCallbacks) {
     488          15 :     callback->sendFailure(Response::Error("Execution context was destroyed."));
     489           5 :     delete callback;
     490             :   }
     491             :   m_evaluateCallbacks.clear();
     492        2944 : }
     493             : 
     494         515 : std::unique_ptr<EvaluateCallback> InjectedScript::takeEvaluateCallback(
     495             :     EvaluateCallback* callback) {
     496             :   auto it = m_evaluateCallbacks.find(callback);
     497         515 :   if (it == m_evaluateCallbacks.end()) return nullptr;
     498         515 :   std::unique_ptr<EvaluateCallback> value(*it);
     499             :   m_evaluateCallbacks.erase(it);
     500             :   return value;
     501             : }
     502             : 
     503       68696 : Response InjectedScript::findObject(const RemoteObjectId& objectId,
     504             :                                     v8::Local<v8::Value>* outObject) const {
     505      137392 :   auto it = m_idToWrappedObject.find(objectId.id());
     506       68696 :   if (it == m_idToWrappedObject.end())
     507           0 :     return Response::Error("Could not find object with given id");
     508      137392 :   *outObject = it->second.Get(m_context->isolate());
     509       68696 :   return Response::OK();
     510             : }
     511             : 
     512       68656 : String16 InjectedScript::objectGroupName(const RemoteObjectId& objectId) const {
     513       68656 :   if (objectId.id() <= 0) return String16();
     514      137312 :   auto it = m_idToObjectGroupName.find(objectId.id());
     515       68656 :   return it != m_idToObjectGroupName.end() ? it->second : String16();
     516             : }
     517             : 
     518       41296 : void InjectedScript::releaseObjectGroup(const String16& objectGroup) {
     519       82592 :   if (objectGroup == "console") m_lastEvaluationResult.Reset();
     520       41296 :   if (objectGroup.isEmpty()) return;
     521             :   auto it = m_nameToObjectGroup.find(objectGroup);
     522       41296 :   if (it == m_nameToObjectGroup.end()) return;
     523     2024919 :   for (int id : it->second) unbindObject(id);
     524             :   m_nameToObjectGroup.erase(it);
     525             : }
     526             : 
     527         345 : void InjectedScript::setCustomObjectFormatterEnabled(bool enabled) {
     528         690 :   v8::HandleScope handles(m_context->isolate());
     529             :   V8FunctionCall function(m_context->inspector(), m_context->context(),
     530        1035 :                           v8Value(), "setCustomObjectFormatterEnabled");
     531         345 :   function.appendArgument(enabled);
     532         345 :   bool hadException = false;
     533         345 :   function.call(hadException);
     534         345 :   DCHECK(!hadException);
     535         345 : }
     536             : 
     537      550348 : v8::Local<v8::Value> InjectedScript::v8Value() const {
     538     1100696 :   return m_value.Get(m_context->isolate());
     539             : }
     540             : 
     541          85 : v8::Local<v8::Value> InjectedScript::lastEvaluationResult() const {
     542          85 :   if (m_lastEvaluationResult.IsEmpty())
     543          20 :     return v8::Undefined(m_context->isolate());
     544          75 :   return m_lastEvaluationResult.Get(m_context->isolate());
     545             : }
     546             : 
     547           5 : void InjectedScript::setLastEvaluationResult(v8::Local<v8::Value> result) {
     548           5 :   m_lastEvaluationResult.Reset(m_context->isolate(), result);
     549           5 : }
     550             : 
     551         276 : Response InjectedScript::resolveCallArgument(
     552             :     protocol::Runtime::CallArgument* callArgument,
     553             :     v8::Local<v8::Value>* result) {
     554         276 :   if (callArgument->hasObjectId()) {
     555          40 :     std::unique_ptr<RemoteObjectId> remoteObjectId;
     556             :     Response response =
     557         120 :         RemoteObjectId::parse(callArgument->getObjectId(""), &remoteObjectId);
     558          40 :     if (!response.isSuccess()) return response;
     559         271 :     if (remoteObjectId->contextId() != m_context->contextId())
     560             :       return Response::Error(
     561             :           "Argument should belong to the same JavaScript world as target "
     562           0 :           "object");
     563          40 :     return findObject(*remoteObjectId, result);
     564             :   }
     565         246 :   if (callArgument->hasValue() || callArgument->hasUnserializableValue()) {
     566             :     String16 value =
     567             :         callArgument->hasValue()
     568         909 :             ? "(" + callArgument->getValue(nullptr)->serialize() + ")"
     569         934 :             : "Number(\"" + callArgument->getUnserializableValue("") + "\")";
     570         231 :     if (!m_context->inspector()
     571             :              ->compileAndRunInternalScript(
     572         231 :                  m_context->context(), toV8String(m_context->isolate(), value))
     573         231 :              .ToLocal(result)) {
     574           0 :       return Response::Error("Couldn't parse value object in call argument");
     575             :     }
     576         231 :     return Response::OK();
     577             :   }
     578          10 :   *result = v8::Undefined(m_context->isolate());
     579           5 :   return Response::OK();
     580             : }
     581             : 
     582        1027 : Response InjectedScript::createExceptionDetails(
     583             :     const v8::TryCatch& tryCatch, const String16& objectGroup,
     584             :     bool generatePreview, Maybe<protocol::Runtime::ExceptionDetails>* result) {
     585        1027 :   if (!tryCatch.HasCaught()) return Response::InternalError();
     586        1027 :   v8::Local<v8::Message> message = tryCatch.Message();
     587        1027 :   v8::Local<v8::Value> exception = tryCatch.Exception();
     588             :   String16 messageText =
     589        1027 :       message.IsEmpty() ? String16() : toProtocolString(message->Get());
     590             :   std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails =
     591             :       protocol::Runtime::ExceptionDetails::create()
     592        3081 :           .setExceptionId(m_context->inspector()->nextExceptionId())
     593        2054 :           .setText(exception.IsEmpty() ? messageText : String16("Uncaught"))
     594             :           .setLineNumber(
     595             :               message.IsEmpty()
     596             :                   ? 0
     597        2054 :                   : message->GetLineNumber(m_context->context()).FromMaybe(1) -
     598        2054 :                         1)
     599             :           .setColumnNumber(
     600             :               message.IsEmpty()
     601             :                   ? 0
     602        3131 :                   : message->GetStartColumn(m_context->context()).FromMaybe(0))
     603             :           .build();
     604        1027 :   if (!message.IsEmpty()) {
     605             :     exceptionDetails->setScriptId(String16::fromInteger(
     606        2054 :         static_cast<int>(message->GetScriptOrigin().ScriptID()->Value())));
     607        1027 :     v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace();
     608        1027 :     if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0)
     609             :       exceptionDetails->setStackTrace(m_context->inspector()
     610             :                                           ->debugger()
     611             :                                           ->createStackTrace(stackTrace)
     612         250 :                                           ->buildInspectorObjectImpl());
     613             :   }
     614        1027 :   if (!exception.IsEmpty()) {
     615        1027 :     std::unique_ptr<protocol::Runtime::RemoteObject> wrapped;
     616             :     Response response =
     617             :         wrapObject(exception, objectGroup, false /* forceValueType */,
     618        1027 :                    generatePreview && !exception->IsNativeError(), &wrapped);
     619        1027 :     if (!response.isSuccess()) return response;
     620             :     exceptionDetails->setException(std::move(wrapped));
     621             :   }
     622             :   *result = std::move(exceptionDetails);
     623        1027 :   return Response::OK();
     624             : }
     625             : 
     626       15152 : Response InjectedScript::wrapEvaluateResult(
     627             :     v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch& tryCatch,
     628             :     const String16& objectGroup, bool returnByValue, bool generatePreview,
     629             :     std::unique_ptr<protocol::Runtime::RemoteObject>* result,
     630             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
     631             :   v8::Local<v8::Value> resultValue;
     632       15152 :   if (!tryCatch.HasCaught()) {
     633       14145 :     if (!maybeResultValue.ToLocal(&resultValue))
     634           0 :       return Response::InternalError();
     635             :     Response response = wrapObject(resultValue, objectGroup, returnByValue,
     636       14145 :                                    generatePreview, result);
     637       14145 :     if (!response.isSuccess()) return response;
     638       28290 :     if (objectGroup == "console")
     639         175 :       m_lastEvaluationResult.Reset(m_context->isolate(), resultValue);
     640             :   } else {
     641        1007 :     v8::Local<v8::Value> exception = tryCatch.Exception();
     642             :     Response response =
     643             :         wrapObject(exception, objectGroup, false,
     644        1007 :                    generatePreview && !exception->IsNativeError(), result);
     645        1007 :     if (!response.isSuccess()) return response;
     646             :     // We send exception in result for compatibility reasons, even though it's
     647             :     // accessible through exceptionDetails.exception.
     648        2004 :     response = createExceptionDetails(tryCatch, objectGroup, generatePreview,
     649             :                                       exceptionDetails);
     650        1002 :     if (!response.isSuccess()) return response;
     651             :   }
     652       15147 :   return Response::OK();
     653             : }
     654             : 
     655         400 : v8::Local<v8::Object> InjectedScript::commandLineAPI() {
     656         400 :   if (m_commandLineAPI.IsEmpty()) {
     657             :     m_commandLineAPI.Reset(
     658             :         m_context->isolate(),
     659             :         m_context->inspector()->console()->createCommandLineAPI(
     660          60 :             m_context->context(), m_sessionId));
     661             :   }
     662         800 :   return m_commandLineAPI.Get(m_context->isolate());
     663             : }
     664             : 
     665      335972 : InjectedScript::Scope::Scope(V8InspectorSessionImpl* session)
     666             :     : m_inspector(session->inspector()),
     667             :       m_injectedScript(nullptr),
     668             :       m_handleScope(m_inspector->isolate()),
     669             :       m_tryCatch(m_inspector->isolate()),
     670             :       m_ignoreExceptionsAndMuteConsole(false),
     671             :       m_previousPauseOnExceptionsState(v8::debug::NoBreakOnException),
     672             :       m_userGesture(false),
     673             :       m_contextGroupId(session->contextGroupId()),
     674      419965 :       m_sessionId(session->sessionId()) {}
     675             : 
     676      100130 : Response InjectedScript::Scope::initialize() {
     677      100130 :   cleanup();
     678             :   V8InspectorSessionImpl* session =
     679      100130 :       m_inspector->sessionById(m_contextGroupId, m_sessionId);
     680      100130 :   if (!session) return Response::InternalError();
     681      100125 :   Response response = findInjectedScript(session);
     682      100125 :   if (!response.isSuccess()) return response;
     683      100100 :   m_context = m_injectedScript->context()->context();
     684      100100 :   m_context->Enter();
     685      100100 :   return Response::OK();
     686             : }
     687             : 
     688         400 : void InjectedScript::Scope::installCommandLineAPI() {
     689             :   DCHECK(m_injectedScript && !m_context.IsEmpty() &&
     690             :          !m_commandLineAPIScope.get());
     691             :   m_commandLineAPIScope.reset(new V8Console::CommandLineAPIScope(
     692        1200 :       m_context, m_injectedScript->commandLineAPI(), m_context->Global()));
     693         400 : }
     694             : 
     695       67101 : void InjectedScript::Scope::ignoreExceptionsAndMuteConsole() {
     696             :   DCHECK(!m_ignoreExceptionsAndMuteConsole);
     697       67101 :   m_ignoreExceptionsAndMuteConsole = true;
     698       67101 :   m_inspector->client()->muteMetrics(m_contextGroupId);
     699       67101 :   m_inspector->muteExceptions(m_contextGroupId);
     700             :   m_previousPauseOnExceptionsState =
     701       67101 :       setPauseOnExceptionsState(v8::debug::NoBreakOnException);
     702       67101 : }
     703             : 
     704      134202 : v8::debug::ExceptionBreakState InjectedScript::Scope::setPauseOnExceptionsState(
     705             :     v8::debug::ExceptionBreakState newState) {
     706      268404 :   if (!m_inspector->debugger()->enabled()) return newState;
     707             :   v8::debug::ExceptionBreakState presentState =
     708      267124 :       m_inspector->debugger()->getPauseOnExceptionsState();
     709      133562 :   if (presentState != newState)
     710         560 :     m_inspector->debugger()->setPauseOnExceptionsState(newState);
     711      133562 :   return presentState;
     712             : }
     713             : 
     714           0 : void InjectedScript::Scope::pretendUserGesture() {
     715             :   DCHECK(!m_userGesture);
     716           0 :   m_userGesture = true;
     717           0 :   m_inspector->client()->beginUserGesture();
     718           0 : }
     719             : 
     720      184123 : void InjectedScript::Scope::cleanup() {
     721             :   m_commandLineAPIScope.reset();
     722      184123 :   if (!m_context.IsEmpty()) {
     723      100100 :     m_context->Exit();
     724             :     m_context.Clear();
     725             :   }
     726      184123 : }
     727             : 
     728      167986 : InjectedScript::Scope::~Scope() {
     729       83993 :   if (m_ignoreExceptionsAndMuteConsole) {
     730       67101 :     setPauseOnExceptionsState(m_previousPauseOnExceptionsState);
     731       67101 :     m_inspector->client()->unmuteMetrics(m_contextGroupId);
     732       67101 :     m_inspector->unmuteExceptions(m_contextGroupId);
     733             :   }
     734       83993 :   if (m_userGesture) m_inspector->client()->endUserGesture();
     735       83993 :   cleanup();
     736       83993 : }
     737             : 
     738        5914 : InjectedScript::ContextScope::ContextScope(V8InspectorSessionImpl* session,
     739             :                                            int executionContextId)
     740             :     : InjectedScript::Scope(session),
     741        6434 :       m_executionContextId(executionContextId) {}
     742             : 
     743        6434 : InjectedScript::ContextScope::~ContextScope() {}
     744             : 
     745       12048 : Response InjectedScript::ContextScope::findInjectedScript(
     746             :     V8InspectorSessionImpl* session) {
     747       12048 :   return session->findInjectedScript(m_executionContextId, m_injectedScript);
     748             : }
     749             : 
     750       67691 : InjectedScript::ObjectScope::ObjectScope(V8InspectorSessionImpl* session,
     751             :                                          const String16& remoteObjectId)
     752      135382 :     : InjectedScript::Scope(session), m_remoteObjectId(remoteObjectId) {}
     753             : 
     754      135382 : InjectedScript::ObjectScope::~ObjectScope() {}
     755             : 
     756       68656 : Response InjectedScript::ObjectScope::findInjectedScript(
     757             :     V8InspectorSessionImpl* session) {
     758       68656 :   std::unique_ptr<RemoteObjectId> remoteId;
     759       68656 :   Response response = RemoteObjectId::parse(m_remoteObjectId, &remoteId);
     760       68656 :   if (!response.isSuccess()) return response;
     761       68656 :   InjectedScript* injectedScript = nullptr;
     762      137312 :   response = session->findInjectedScript(remoteId.get(), injectedScript);
     763       68656 :   if (!response.isSuccess()) return response;
     764      137312 :   m_objectGroupName = injectedScript->objectGroupName(*remoteId);
     765      205968 :   response = injectedScript->findObject(*remoteId, &m_object);
     766       68656 :   if (!response.isSuccess()) return response;
     767       68656 :   m_injectedScript = injectedScript;
     768       68656 :   return Response::OK();
     769             : }
     770             : 
     771        9868 : InjectedScript::CallFrameScope::CallFrameScope(V8InspectorSessionImpl* session,
     772             :                                                const String16& remoteObjectId)
     773        9868 :     : InjectedScript::Scope(session), m_remoteCallFrameId(remoteObjectId) {}
     774             : 
     775       19736 : InjectedScript::CallFrameScope::~CallFrameScope() {}
     776             : 
     777       19421 : Response InjectedScript::CallFrameScope::findInjectedScript(
     778             :     V8InspectorSessionImpl* session) {
     779       19421 :   std::unique_ptr<RemoteCallFrameId> remoteId;
     780       19421 :   Response response = RemoteCallFrameId::parse(m_remoteCallFrameId, &remoteId);
     781       19421 :   if (!response.isSuccess()) return response;
     782       19421 :   m_frameOrdinal = static_cast<size_t>(remoteId->frameOrdinal());
     783       19421 :   return session->findInjectedScript(remoteId.get(), m_injectedScript);
     784             : }
     785             : 
     786     2540233 : InjectedScript* InjectedScript::fromInjectedScriptHost(
     787             :     v8::Isolate* isolate, v8::Local<v8::Object> injectedScriptObject) {
     788     2540233 :   v8::HandleScope handleScope(isolate);
     789     2540233 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
     790             :   v8::Local<v8::Private> privateKey = v8::Private::ForApi(
     791             :       isolate, v8::String::NewFromUtf8(isolate, privateKeyName,
     792             :                                        v8::NewStringType::kInternalized)
     793     5080466 :                    .ToLocalChecked());
     794             :   v8::Local<v8::Value> value =
     795     2540233 :       injectedScriptObject->GetPrivate(context, privateKey).ToLocalChecked();
     796             :   DCHECK(value->IsExternal());
     797             :   v8::Local<v8::External> external = value.As<v8::External>();
     798     2540233 :   return static_cast<InjectedScript*>(external->Value());
     799             : }
     800             : 
     801     2540233 : int InjectedScript::bindObject(v8::Local<v8::Value> value,
     802             :                                const String16& groupName) {
     803     2540233 :   if (m_lastBoundObjectId <= 0) m_lastBoundObjectId = 1;
     804     2540233 :   int id = m_lastBoundObjectId++;
     805     2540233 :   m_idToWrappedObject[id].Reset(m_context->isolate(), value);
     806             : 
     807     2540233 :   if (!groupName.isEmpty() && id > 0) {
     808     2531245 :     m_idToObjectGroupName[id] = groupName;
     809     2531245 :     m_nameToObjectGroup[groupName].push_back(id);
     810             :   }
     811     2540233 :   return id;
     812             : }
     813             : 
     814           0 : void InjectedScript::unbindObject(int id) {
     815             :   m_idToWrappedObject.erase(id);
     816             :   m_idToObjectGroupName.erase(id);
     817           0 : }
     818             : 
     819             : }  // namespace v8_inspector

Generated by: LCOV version 1.10