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