• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PepperTryCatch(PepperPluginInstanceImpl * instance,V8VarConverter::AllowObjectVars convert_objects)22 PepperTryCatch::PepperTryCatch(PepperPluginInstanceImpl* instance,
23                                V8VarConverter::AllowObjectVars convert_objects)
24     : instance_(instance),
25       convert_objects_(convert_objects) {}
26 
~PepperTryCatch()27 PepperTryCatch::~PepperTryCatch() {}
28 
ToV8(PP_Var var)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 
FromV8(v8::Handle<v8::Value> v8_value)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 
PepperTryCatchV8(PepperPluginInstanceImpl * instance,V8VarConverter::AllowObjectVars convert_objects,v8::Isolate * isolate)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 
~PepperTryCatchV8()76 PepperTryCatchV8::~PepperTryCatchV8() {
77   ppapi::PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(exception_);
78 }
79 
HasException()80 bool PepperTryCatchV8::HasException() {
81   return GetContext().IsEmpty() || exception_.type != PP_VARTYPE_UNDEFINED;
82 }
83 
GetContext()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 
ThrowException()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 
ThrowException(const char * message)110 void PepperTryCatchV8::ThrowException(const char* message) {
111   SetException(message);
112   ThrowException();
113 }
114 
SetException(const char * message)115 void PepperTryCatchV8::SetException(const char* message) {
116   if (HasException())
117     return;
118 
119   exception_ = ppapi::StringVar::StringToPPVar(message);
120 }
121 
PepperTryCatchVar(PepperPluginInstanceImpl * instance,PP_Var * exception)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 
~PepperTryCatchVar()134 PepperTryCatchVar::~PepperTryCatchVar() {
135   if (!context_.IsEmpty())
136     context_->Exit();
137 }
138 
HasException()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 
GetContext()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 
SetException(const char * message)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