summaryrefslogtreecommitdiffstats
path: root/chromium/content/renderer/pepper/pepper_try_catch.cc
blob: 4f8bd7ea18e5bb2fdd7ecfc612f29092a1f2eece (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/pepper/pepper_try_catch.h"

#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "content/renderer/pepper/v8_var_converter.h"
#include "gin/converter.h"
#include "ppapi/shared_impl/ppapi_globals.h"
#include "ppapi/shared_impl/var_tracker.h"

namespace content {

namespace {

const char kConversionException[] =
    "Error: Failed conversion between PP_Var and V8 value";
const char kInvalidException[] = "Error: An invalid exception was thrown.";

}  // namespace

PepperTryCatch::PepperTryCatch(PepperPluginInstanceImpl* instance,
                               V8VarConverter* var_converter)
    : instance_(instance), var_converter_(var_converter) {}

PepperTryCatch::~PepperTryCatch() {}

v8::Local<v8::Value> PepperTryCatch::ToV8(PP_Var var) {
  if (HasException()) {
    SetException(kConversionException);
    return v8::Local<v8::Value>();
  }

  v8::Local<v8::Value> result;
  bool success = var_converter_->ToV8Value(var, GetContext(), &result);
  if (!success) {
    SetException(kConversionException);
    return v8::Local<v8::Value>();
  }
  return result;
}

ppapi::ScopedPPVar PepperTryCatch::FromV8(v8::Local<v8::Value> v8_value) {
  if (HasException() || v8_value.IsEmpty()) {
    SetException(kConversionException);
    return ppapi::ScopedPPVar();
  }
  ppapi::ScopedPPVar result;
  bool success =
      var_converter_->FromV8ValueSync(v8_value, GetContext(), &result);
  if (!success) {
    SetException(kConversionException);
    return ppapi::ScopedPPVar();
  }
  return result;
}

PepperTryCatchV8::PepperTryCatchV8(PepperPluginInstanceImpl* instance,
                                   V8VarConverter* var_converter,
                                   v8::Isolate* isolate)
    : PepperTryCatch(instance, var_converter),
      exception_(PP_MakeUndefined()) {
  // Typically when using PepperTryCatchV8 we are passed an isolate. We verify
  // that this isolate is the same as the plugin isolate.
  DCHECK(isolate == instance_->GetIsolate());

  // We assume that a handle scope and context has been setup by the user of
  // this class. This is typically true because this class is used when calling
  // into the plugin from JavaScript. We want to use whatever v8 context the
  // caller is in.
}

PepperTryCatchV8::~PepperTryCatchV8() {
  ppapi::PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(exception_);
}

bool PepperTryCatchV8::HasException() {
  return GetContext().IsEmpty() || exception_.type != PP_VARTYPE_UNDEFINED;
}

v8::Local<v8::Context> PepperTryCatchV8::GetContext() {
  // When calling from JS into the plugin always use the current context.
  return instance_->GetIsolate()->GetCurrentContext();
}

bool PepperTryCatchV8::ThrowException() {
  if (!HasException())
    return false;

  // If there is no context then we have an exception but we don't try to throw
  // it into v8.
  if (GetContext().IsEmpty())
    return true;

  std::string message(kInvalidException);
  ppapi::StringVar* message_var = ppapi::StringVar::FromPPVar(exception_);
  if (message_var)
    message = message_var->value();
  instance_->GetIsolate()->ThrowException(v8::Exception::Error(
      gin::StringToV8(instance_->GetIsolate(), message)));

  ppapi::PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(exception_);
  exception_ = PP_MakeUndefined();
  return true;
}

void PepperTryCatchV8::ThrowException(const char* message) {
  SetException(message);
  ThrowException();
}

void PepperTryCatchV8::SetException(const char* message) {
  if (HasException())
    return;

  exception_ = ppapi::StringVar::StringToPPVar(message);
}

PepperTryCatchVar::PepperTryCatchVar(PepperPluginInstanceImpl* instance,
                                     V8VarConverter* var_converter,
                                     PP_Var* exception)
    : PepperTryCatch(instance, var_converter),
      handle_scope_(instance_->GetIsolate()),
      try_catch_(instance_->GetIsolate()),
      exception_(exception),
      exception_is_set_(false) {
  // Store a handle to the context here for 2 reasons:
  // 1) To hold a handle to it in case all other handles are destroyed.
  // 2) Because calling PepperPluginInstanceImpl::GetMainWorldContext() later
  //    can result in trying to access the plugin element. However the plugin
  //    element may have been destroyed during the PepperTryCatchVar (for
  //    example if a script is executed which destroys the plugin element). So
  //    we want to avoid accessing the plugin element again beyond this point.
  context_ = instance_->GetMainWorldContext();

  // We switch to the plugin context if it's not empty.
  if (!context_.IsEmpty())
    context_->Enter();
}

PepperTryCatchVar::~PepperTryCatchVar() {
  if (!context_.IsEmpty())
    context_->Exit();
}

bool PepperTryCatchVar::HasException() {
  if (exception_is_set_)
    return true;

  std::string exception_message;
  if (context_.IsEmpty()) {
    exception_message = "The v8 context has been destroyed.";
  } else if (try_catch_.HasCaught()) {
    v8::Local<v8::Message> message(try_catch_.Message());
    if (!message.IsEmpty()) {
      v8::String::Utf8Value utf8(handle_scope_.GetIsolate(),
                                 try_catch_.Message()->Get());
      exception_message = std::string(*utf8, utf8.length());
    } else {
      exception_message = "There was a v8 exception.";
    }
  }

  if (!exception_message.empty()) {
    exception_is_set_ = true;
    if (exception_)
      *exception_ = ppapi::StringVar::StringToPPVar(exception_message);
  }

  return exception_is_set_;
}

v8::Local<v8::Context> PepperTryCatchVar::GetContext() {
  return context_;
}

void PepperTryCatchVar::SetException(const char* message) {
  if (exception_is_set_)
    return;

  if (exception_)
    *exception_ = ppapi::StringVar::StringToPPVar(message, strlen(message));
  exception_is_set_ = true;
}

}  // namespace content