Home | History | Annotate | Download | only in pepper
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/renderer/pepper/pepper_try_catch.h"
      6 
      7 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
      8 #include "gin/converter.h"
      9 #include "ppapi/shared_impl/ppapi_globals.h"
     10 #include "ppapi/shared_impl/var_tracker.h"
     11 
     12 namespace content {
     13 
     14 namespace {
     15 
     16 const char kConversionException[] =
     17     "Error: Failed conversion between PP_Var and V8 value";
     18 const char kInvalidException[] = "Error: An invalid exception was thrown.";
     19 
     20 }  // namespace
     21 
     22 PepperTryCatch::PepperTryCatch(PepperPluginInstanceImpl* instance,
     23                                V8VarConverter::AllowObjectVars convert_objects)
     24     : instance_(instance),
     25       convert_objects_(convert_objects) {}
     26 
     27 PepperTryCatch::~PepperTryCatch() {}
     28 
     29 v8::Handle<v8::Value> PepperTryCatch::ToV8(PP_Var var) {
     30   if (HasException()) {
     31     SetException(kConversionException);
     32     return v8::Handle<v8::Value>();
     33   }
     34 
     35   V8VarConverter converter(instance_->pp_instance(), convert_objects_);
     36   v8::Handle<v8::Value> result;
     37   bool success = converter.ToV8Value(var, GetContext(), &result);
     38   if (!success) {
     39     SetException(kConversionException);
     40     return v8::Handle<v8::Value>();
     41   }
     42   return result;
     43 }
     44 
     45 ppapi::ScopedPPVar PepperTryCatch::FromV8(v8::Handle<v8::Value> v8_value) {
     46   if (HasException() || v8_value.IsEmpty()) {
     47     SetException(kConversionException);
     48     return ppapi::ScopedPPVar();
     49   }
     50   ppapi::ScopedPPVar result;
     51   V8VarConverter converter(instance_->pp_instance(), convert_objects_);
     52   bool success = converter.FromV8ValueSync(v8_value, GetContext(), &result);
     53   if (!success) {
     54     SetException(kConversionException);
     55     return ppapi::ScopedPPVar();
     56   }
     57   return result;
     58 }
     59 
     60 PepperTryCatchV8::PepperTryCatchV8(
     61     PepperPluginInstanceImpl* instance,
     62     V8VarConverter::AllowObjectVars convert_objects,
     63     v8::Isolate* isolate)
     64     : PepperTryCatch(instance, convert_objects),
     65       exception_(PP_MakeUndefined()) {
     66   // Typically when using PepperTryCatchV8 we are passed an isolate. We verify
     67   // that this isolate is the same as the plugin isolate.
     68   DCHECK(isolate == instance_->GetIsolate());
     69 
     70   // We assume that a handle scope and context has been setup by the user of
     71   // this class. This is typically true because this class is used when calling
     72   // into the plugin from JavaScript. We want to use whatever v8 context the
     73   // caller is in.
     74 }
     75 
     76 PepperTryCatchV8::~PepperTryCatchV8() {
     77   ppapi::PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(exception_);
     78 }
     79 
     80 bool PepperTryCatchV8::HasException() {
     81   return GetContext().IsEmpty() || exception_.type != PP_VARTYPE_UNDEFINED;
     82 }
     83 
     84 v8::Handle<v8::Context> PepperTryCatchV8::GetContext() {
     85   // When calling from JS into the plugin always use the current context.
     86   return instance_->GetIsolate()->GetCurrentContext();
     87 }
     88 
     89 bool PepperTryCatchV8::ThrowException() {
     90   if (!HasException())
     91     return false;
     92 
     93   // If there is no context then we have an exception but we don't try to throw
     94   // it into v8.
     95   if (GetContext().IsEmpty())
     96     return true;
     97 
     98   std::string message(kInvalidException);
     99   ppapi::StringVar* message_var = ppapi::StringVar::FromPPVar(exception_);
    100   if (message_var)
    101     message = message_var->value();
    102   instance_->GetIsolate()->ThrowException(v8::Exception::Error(
    103       gin::StringToV8(instance_->GetIsolate(), message)));
    104 
    105   ppapi::PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(exception_);
    106   exception_ = PP_MakeUndefined();
    107   return true;
    108 }
    109 
    110 void PepperTryCatchV8::ThrowException(const char* message) {
    111   SetException(message);
    112   ThrowException();
    113 }
    114 
    115 void PepperTryCatchV8::SetException(const char* message) {
    116   if (HasException())
    117     return;
    118 
    119   exception_ = ppapi::StringVar::StringToPPVar(message);
    120 }
    121 
    122 PepperTryCatchVar::PepperTryCatchVar(PepperPluginInstanceImpl* instance,
    123                                      PP_Var* exception)
    124     : PepperTryCatch(instance, V8VarConverter::kAllowObjectVars),
    125       handle_scope_(instance_->GetIsolate()),
    126       context_(GetContext()),
    127       exception_(exception),
    128       exception_is_set_(false) {
    129   // We switch to the plugin context if it's not empty.
    130   if (!context_.IsEmpty())
    131     context_->Enter();
    132 }
    133 
    134 PepperTryCatchVar::~PepperTryCatchVar() {
    135   if (!context_.IsEmpty())
    136     context_->Exit();
    137 }
    138 
    139 bool PepperTryCatchVar::HasException() {
    140   if (exception_is_set_)
    141     return true;
    142 
    143   std::string exception_message;
    144   if (GetContext().IsEmpty()) {
    145     exception_message = "The v8 context has been destroyed.";
    146   } else if (try_catch_.HasCaught()) {
    147     v8::String::Utf8Value utf8(try_catch_.Message()->Get());
    148     exception_message = std::string(*utf8, utf8.length());
    149   }
    150 
    151   if (!exception_message.empty()) {
    152     exception_is_set_ = true;
    153     if (exception_)
    154       *exception_ = ppapi::StringVar::StringToPPVar(exception_message);
    155   }
    156 
    157   return exception_is_set_;
    158 }
    159 
    160 v8::Handle<v8::Context> PepperTryCatchVar::GetContext() {
    161   // When calling into JS from the plugin, always use the plugin context.
    162   return instance_->GetMainWorldContext();
    163 }
    164 
    165 void PepperTryCatchVar::SetException(const char* message) {
    166   if (exception_is_set_)
    167     return;
    168 
    169   if (exception_)
    170     *exception_ = ppapi::StringVar::StringToPPVar(message, strlen(message));
    171   exception_is_set_ = true;
    172 }
    173 
    174 }  // namespace content
    175