summaryrefslogtreecommitdiffstats
path: root/ppapi
diff options
context:
space:
mode:
Diffstat (limited to 'ppapi')
-rw-r--r--ppapi/api/ppb_messaging.idl4
-rw-r--r--ppapi/api/ppp_messaging.idl7
-rw-r--r--ppapi/c/ppb_messaging.h6
-rw-r--r--ppapi/c/ppp_messaging.h9
-rw-r--r--ppapi/cpp/instance.h24
-rw-r--r--ppapi/proxy/handle_converter.cc8
-rw-r--r--ppapi/proxy/ppb_instance_proxy.cc10
-rw-r--r--ppapi/proxy/raw_var_data.cc77
-rw-r--r--ppapi/proxy/raw_var_data.h2
-rw-r--r--ppapi/proxy/raw_var_data_unittest.cc32
-rw-r--r--ppapi/proxy/serialized_var.cc39
-rw-r--r--ppapi/proxy/serialized_var.h31
-rw-r--r--ppapi/tests/test_post_message.cc48
-rw-r--r--ppapi/tests/test_post_message.h4
14 files changed, 215 insertions, 86 deletions
diff --git a/ppapi/api/ppb_messaging.idl b/ppapi/api/ppb_messaging.idl
index 647f7f6..0f9a3aa 100644
--- a/ppapi/api/ppb_messaging.idl
+++ b/ppapi/api/ppb_messaging.idl
@@ -36,8 +36,8 @@ interface PPB_Messaging {
* JavaScript.
*
* When passing array or dictionary <code>PP_Var</code>s, the entire reference
- * graph will be converted and transferred, including reference cycles if they
- * exist.
+ * graph will be converted and transferred. If the reference graph has cycles,
+ * the message will not be sent and an error will be logged to the console.
*
* Listeners for message events in JavaScript code will receive an object
* conforming to the HTML 5 <code>MessageEvent</code> interface.
diff --git a/ppapi/api/ppp_messaging.idl b/ppapi/api/ppp_messaging.idl
index 150f771..83c2010 100644
--- a/ppapi/api/ppp_messaging.idl
+++ b/ppapi/api/ppp_messaging.idl
@@ -36,10 +36,9 @@ interface PPP_Messaging {
*
* When converting JavaScript arrays, any object properties whose name
* is not an array index are ignored. When passing arrays and objects, the
- * entire reference graph will be converted and transferred, including
- * reference cycles if they exist. Since <code>PP_Var</code>s are ref-counted,
- * the author of the plugin must take care if they expect to receive vars with
- * cycles. Cycles must be manually broken to correctly release the vars.
+ * entire reference graph will be converted and transferred. If the reference
+ * graph has cycles, the message will not be sent and an error will be logged
+ * to the console.
*
* The following JavaScript code invokes <code>HandleMessage</code>, passing
* the module instance on which it was invoked, with <code>message</code>
diff --git a/ppapi/c/ppb_messaging.h b/ppapi/c/ppb_messaging.h
index 404a11c..06e31205 100644
--- a/ppapi/c/ppb_messaging.h
+++ b/ppapi/c/ppb_messaging.h
@@ -3,7 +3,7 @@
* found in the LICENSE file.
*/
-/* From ppb_messaging.idl modified Mon May 20 15:31:07 2013. */
+/* From ppb_messaging.idl modified Wed Jun 5 10:32:59 2013. */
#ifndef PPAPI_C_PPB_MESSAGING_H_
#define PPAPI_C_PPB_MESSAGING_H_
@@ -50,8 +50,8 @@ struct PPB_Messaging_1_0 {
* JavaScript.
*
* When passing array or dictionary <code>PP_Var</code>s, the entire reference
- * graph will be converted and transferred, including reference cycles if they
- * exist.
+ * graph will be converted and transferred. If the reference graph has cycles,
+ * the message will not be sent and an error will be logged to the console.
*
* Listeners for message events in JavaScript code will receive an object
* conforming to the HTML 5 <code>MessageEvent</code> interface.
diff --git a/ppapi/c/ppp_messaging.h b/ppapi/c/ppp_messaging.h
index b2e1f3c..28d40d6 100644
--- a/ppapi/c/ppp_messaging.h
+++ b/ppapi/c/ppp_messaging.h
@@ -3,7 +3,7 @@
* found in the LICENSE file.
*/
-/* From ppp_messaging.idl modified Tue May 21 09:01:17 2013. */
+/* From ppp_messaging.idl modified Wed Jun 5 10:32:43 2013. */
#ifndef PPAPI_C_PPP_MESSAGING_H_
#define PPAPI_C_PPP_MESSAGING_H_
@@ -52,10 +52,9 @@ struct PPP_Messaging_1_0 {
*
* When converting JavaScript arrays, any object properties whose name
* is not an array index are ignored. When passing arrays and objects, the
- * entire reference graph will be converted and transferred, including
- * reference cycles if they exist. Since <code>PP_Var</code>s are ref-counted,
- * the author of the plugin must take care if they expect to receive vars with
- * cycles. Cycles must be manually broken to correctly release the vars.
+ * entire reference graph will be converted and transferred. If the reference
+ * graph has cycles, the message will not be sent and an error will be logged
+ * to the console.
*
* The following JavaScript code invokes <code>HandleMessage</code>, passing
* the module instance on which it was invoked, with <code>message</code>
diff --git a/ppapi/cpp/instance.h b/ppapi/cpp/instance.h
index 48bca90..6bf4e83 100644
--- a/ppapi/cpp/instance.h
+++ b/ppapi/cpp/instance.h
@@ -244,6 +244,12 @@ class Instance {
/// JavaScript execution will not be blocked while HandleMessage() is
/// processing the message.
///
+ /// When converting JavaScript arrays, any object properties whose name
+ /// is not an array index are ignored. When passing arrays and objects, the
+ /// entire reference graph will be converted and transferred. If the reference
+ /// graph has cycles, the message will not be sent and an error will be logged
+ /// to the console.
+ ///
/// <strong>Example:</strong>
///
/// The following JavaScript code invokes <code>HandleMessage</code>, passing
@@ -264,9 +270,10 @@ class Instance {
///
/// Refer to PostMessage() for sending messages to JavaScript.
///
- /// @param[in] message A <code>Var</code> containing the data sent from
- /// JavaScript. Message can have an int32_t, double, bool, or string value
- /// (objects are not supported).
+ /// @param[in] message A <code>Var</code> which has been converted from a
+ /// JavaScript value. JavaScript array/object types are supported from Chrome
+ /// M29 onward. All JavaScript values are copied when passing them to the
+ /// plugin.
virtual void HandleMessage(const Var& message);
/// @}
@@ -453,6 +460,11 @@ class Instance {
///
/// The browser will pop-up an alert saying "Hello world!"
///
+ /// When passing array or dictionary <code>PP_Var</code>s, the entire
+ /// reference graph will be converted and transferred. If the reference graph
+ /// has cycles, the message will not be sent and an error will be logged to
+ /// the console.
+ ///
/// Listeners for message events in JavaScript code will receive an object
/// conforming to the HTML 5 <code>MessageEvent</code> interface.
/// Specifically, the value of message will be contained as a property called
@@ -466,9 +478,9 @@ class Instance {
/// Refer to HandleMessage() for receiving events from JavaScript.
///
/// @param[in] message A <code>Var</code> containing the data to be sent to
- /// JavaScript. Message can have a numeric, boolean, or string value; arrays
- /// and dictionaries are not yet supported. Ref-counted var types are copied,
- /// and are therefore not shared between the instance and the browser.
+ /// JavaScript. Message can have a numeric, boolean, or string value.
+ /// Array/Dictionary types are supported from Chrome M29 onward.
+ /// All var types are copied when passing them to JavaScript.
void PostMessage(const Var& message);
/// @}
diff --git a/ppapi/proxy/handle_converter.cc b/ppapi/proxy/handle_converter.cc
index b77ee49..d2fc4a9 100644
--- a/ppapi/proxy/handle_converter.cc
+++ b/ppapi/proxy/handle_converter.cc
@@ -54,18 +54,14 @@ void ConvertHandlesInParam(const ppapi::proxy::SerializedVar& var,
Handles* handles,
IPC::Message* msg,
int* handle_index) {
- if (!var.raw_var_data())
- return;
-
- std::vector<ppapi::proxy::SerializedHandle*> var_handles =
- var.raw_var_data()->GetHandles();
+ std::vector<ppapi::proxy::SerializedHandle*> var_handles = var.GetHandles();
if (var_handles.empty())
return;
for (size_t i = 0; i < var_handles.size(); ++i)
handles->push_back(*var_handles[i]);
if (msg)
- var.raw_var_data()->Write(msg, base::Bind(&HandleWriter, handle_index));
+ var.WriteDataToMessage(msg, base::Bind(&HandleWriter, handle_index));
}
// For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall,
diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc
index 4009a19..e3948f06a 100644
--- a/ppapi/proxy/ppb_instance_proxy.cc
+++ b/ppapi/proxy/ppb_instance_proxy.cc
@@ -56,6 +56,10 @@ namespace proxy {
namespace {
+const char kSerializationError[] = "Failed to convert a PostMessage "
+ "argument from a PP_Var to a Javascript value. It may have cycles or be of "
+ "an unsupported type.";
+
InterfaceProxy* CreateInstanceProxy(Dispatcher* dispatcher) {
return new PPB_Instance_Proxy(dispatcher);
}
@@ -933,6 +937,12 @@ void PPB_Instance_Proxy::OnHostMsgPostMessage(
PP_Instance instance,
SerializedVarReceiveInput message) {
EnterInstanceNoLock enter(instance);
+ if (!message.is_valid_var()) {
+ PpapiGlobals::Get()->LogWithSource(
+ instance, PP_LOGLEVEL_ERROR, std::string(), kSerializationError);
+ return;
+ }
+
if (enter.succeeded())
enter.functions()->PostMessage(instance,
message.GetForInstance(dispatcher(),
diff --git a/ppapi/proxy/raw_var_data.cc b/ppapi/proxy/raw_var_data.cc
index 4de51ae..a550c3f 100644
--- a/ppapi/proxy/raw_var_data.cc
+++ b/ppapi/proxy/raw_var_data.cc
@@ -31,25 +31,27 @@ static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024;
static uint32 g_minimum_array_buffer_size_for_shmem =
kMinimumArrayBufferSizeForShmem;
-void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) {
- IPC::ParamTraits<SerializedHandle>::Write(m, handle);
-}
+struct StackEntry {
+ StackEntry(PP_Var v, size_t i) : var(v), data_index(i) {}
+ PP_Var var;
+ size_t data_index;
+};
// For a given PP_Var, returns the RawVarData associated with it, or creates a
// new one if there is no existing one. The data is appended to |data| if it
// is newly created. The index into |data| pointing to the result is returned.
-// |id_map| keeps track of RawVarDatas that have already been created.
+// |visited_map| keeps track of RawVarDatas that have already been created.
size_t GetOrCreateRawVarData(const PP_Var& var,
- base::hash_map<int64_t, size_t>* id_map,
+ base::hash_map<int64_t, size_t>* visited_map,
ScopedVector<RawVarData>* data) {
if (VarTracker::IsVarTypeRefcounted(var.type)) {
- base::hash_map<int64_t, size_t>::iterator it = id_map->find(
+ base::hash_map<int64_t, size_t>::iterator it = visited_map->find(
var.value.as_id);
- if (it != id_map->end()) {
+ if (it != visited_map->end()) {
return it->second;
} else {
data->push_back(RawVarData::Create(var.type));
- (*id_map)[var.value.as_id] = data->size() - 1;
+ (*visited_map)[var.value.as_id] = data->size() - 1;
}
} else {
data->push_back(RawVarData::Create(var.type));
@@ -57,6 +59,10 @@ size_t GetOrCreateRawVarData(const PP_Var& var,
return data->size() - 1;
}
+bool CanHaveChildren(PP_Var var) {
+ return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY;
+}
+
} // namespace
// RawVarDataGraph ------------------------------------------------------------
@@ -66,27 +72,40 @@ RawVarDataGraph::RawVarDataGraph() {
RawVarDataGraph::~RawVarDataGraph() {
}
+// This function uses a stack-based DFS search to traverse the var graph. Each
+// iteration, the top node on the stack examined. If the node has not been
+// visited yet (i.e. !initialized()) then it is added to the list of
+// |parent_ids| which contains all of the nodes on the path from the start node
+// to the current node. Each of that nodes children are examined. If they appear
+// in the list of |parent_ids| it means we have a cycle and we return NULL.
+// Otherwise, if they haven't been visited yet we add them to the stack, If the
+// node at the top of the stack has already been visited, then we pop it off the
+// stack and erase it from |parent_ids|.
// static
scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var,
PP_Instance instance) {
scoped_ptr<RawVarDataGraph> graph(new RawVarDataGraph);
// Map of |var.value.as_id| to a RawVarData index in RawVarDataGraph.
- base::hash_map<int64_t, size_t> id_map;
+ base::hash_map<int64_t, size_t> visited_map;
+ base::hash_set<int64_t> parent_ids;
- std::stack<std::pair<PP_Var, size_t> > stack;
- stack.push(make_pair(var, GetOrCreateRawVarData(var, &id_map,
- &graph->data_)));
+ std::stack<StackEntry> stack;
+ stack.push(StackEntry(var, GetOrCreateRawVarData(var, &visited_map,
+ &graph->data_)));
- // Traverse the PP_Var graph with DFS.
while (!stack.empty()) {
- PP_Var current_var = stack.top().first;
- RawVarData* current_var_data = graph->data_[stack.top().second];
- stack.pop();
+ PP_Var current_var = stack.top().var;
+ RawVarData* current_var_data = graph->data_[stack.top().data_index];
- // If the node is initialized, it means we have visited it.
- if (current_var_data->initialized())
+ if (current_var_data->initialized()) {
+ stack.pop();
+ if (CanHaveChildren(current_var))
+ parent_ids.erase(current_var.value.as_id);
continue;
+ }
+ if (CanHaveChildren(current_var))
+ parent_ids.insert(current_var.value.as_id);
if (!current_var_data->Init(current_var, instance)) {
NOTREACHED();
return scoped_ptr<RawVarDataGraph>();
@@ -103,10 +122,16 @@ scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var,
array_var->elements().begin();
iter != array_var->elements().end();
++iter) {
- size_t child_id = GetOrCreateRawVarData(iter->get(), &id_map,
+ const PP_Var& child = iter->get();
+ // If a child of this node is already in parent_ids, we have a cycle so
+ // we just return null.
+ if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0)
+ return scoped_ptr<RawVarDataGraph>();
+ size_t child_id = GetOrCreateRawVarData(child, &visited_map,
&graph->data_);
static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id);
- stack.push(make_pair(iter->get(), child_id));
+ if (!graph->data_[child_id]->initialized())
+ stack.push(StackEntry(child, child_id));
}
} else if (current_var.type == PP_VARTYPE_DICTIONARY) {
DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
@@ -118,11 +143,15 @@ scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var,
dict_var->key_value_map().begin();
iter != dict_var->key_value_map().end();
++iter) {
- size_t child_id = GetOrCreateRawVarData(iter->second.get(), &id_map,
+ const PP_Var& child = iter->second.get();
+ if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0)
+ return scoped_ptr<RawVarDataGraph>();
+ size_t child_id = GetOrCreateRawVarData(child, &visited_map,
&graph->data_);
static_cast<DictionaryRawVarData*>(
current_var_data)->AddChild(iter->first, child_id);
- stack.push(make_pair(iter->second.get(), child_id));
+ if (!graph->data_[child_id]->initialized())
+ stack.push(StackEntry(child, child_id));
}
}
}
@@ -153,10 +182,6 @@ void RawVarDataGraph::Write(IPC::Message* m,
}
}
-void RawVarDataGraph::Write(IPC::Message* m) {
- Write(m, base::Bind(&DefaultHandleWriter));
-}
-
// static
scoped_ptr<RawVarDataGraph> RawVarDataGraph::Read(const IPC::Message* m,
PickleIterator* iter) {
diff --git a/ppapi/proxy/raw_var_data.h b/ppapi/proxy/raw_var_data.h
index 1e8746f..c7981d3 100644
--- a/ppapi/proxy/raw_var_data.h
+++ b/ppapi/proxy/raw_var_data.h
@@ -65,8 +65,6 @@ class PPAPI_PROXY_EXPORT RawVarDataGraph {
// Write the graph to a message using the given HandleWriter.
void Write(IPC::Message* m, const HandleWriter& handle_writer);
- // Write the graph to a message using the default handle writer.
- void Write(IPC::Message* m);
// Create a RawVarDataGraph from the given message.
static scoped_ptr<RawVarDataGraph> Read(const IPC::Message* m,
diff --git a/ppapi/proxy/raw_var_data_unittest.cc b/ppapi/proxy/raw_var_data_unittest.cc
index 2b134af..2ee6914 100644
--- a/ppapi/proxy/raw_var_data_unittest.cc
+++ b/ppapi/proxy/raw_var_data_unittest.cc
@@ -26,6 +26,10 @@ namespace proxy {
namespace {
+void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) {
+ IPC::ParamTraits<SerializedHandle>::Write(m, handle);
+}
+
class RawVarDataTest : public testing::Test {
public:
RawVarDataTest() {}
@@ -44,21 +48,28 @@ class RawVarDataTest : public testing::Test {
TestGlobals globals_;
};
-PP_Var WriteAndRead(const PP_Var& var) {
+bool WriteAndRead(const PP_Var& var, PP_Var* result) {
PP_Instance dummy_instance = 1234;
scoped_ptr<RawVarDataGraph> expected_data(RawVarDataGraph::Create(
var, dummy_instance));
+ if (!expected_data)
+ return false;
IPC::Message m;
- expected_data->Write(&m);
+ expected_data->Write(&m, base::Bind(&DefaultHandleWriter));
PickleIterator iter(m);
scoped_ptr<RawVarDataGraph> actual_data(RawVarDataGraph::Read(&m, &iter));
- return actual_data->CreatePPVar(dummy_instance);
+ *result = actual_data->CreatePPVar(dummy_instance);
+ return true;
}
// Assumes a ref for var.
bool WriteReadAndCompare(const PP_Var& var) {
ScopedPPVar expected(ScopedPPVar::PassRef(), var);
- ScopedPPVar actual(ScopedPPVar::PassRef(), WriteAndRead(expected.get()));
+ PP_Var result;
+ bool success = WriteAndRead(expected.get(), &result);
+ if (!success)
+ return false;
+ ScopedPPVar actual(ScopedPPVar::PassRef(), result);
return TestEqual(expected.get(), actual.get());
}
@@ -160,25 +171,18 @@ TEST_F(RawVarDataTest, DictionaryArrayTest) {
// Array <-> dictionary cycle.
dictionary->SetWithStringKey("10", release_array.get());
- ScopedPPVar result = ScopedPPVar(ScopedPPVar::PassRef(),
- WriteAndRead(release_dictionary.get()));
- EXPECT_TRUE(TestEqual(release_dictionary.get(), result.get()));
+ PP_Var result;
+ ASSERT_FALSE(WriteAndRead(release_dictionary.get(), &result));
// Break the cycle.
// TODO(raymes): We need some better machinery for releasing vars with
// cycles. Remove the code below once we have that.
dictionary->DeleteWithStringKey("10");
- DictionaryVar* result_dictionary = DictionaryVar::FromPPVar(result.get());
- result_dictionary->DeleteWithStringKey("10");
// Array with self references.
array->Set(index, release_array.get());
- result = ScopedPPVar(ScopedPPVar::PassRef(),
- WriteAndRead(release_array.get()));
- EXPECT_TRUE(TestEqual(release_array.get(), result.get()));
+ ASSERT_FALSE(WriteAndRead(release_array.get(), &result));
// Break the self reference.
array->Set(index, PP_MakeUndefined());
- ArrayVar* result_array = ArrayVar::FromPPVar(result.get());
- result_array->Set(index, PP_MakeUndefined());
}
} // namespace proxy
diff --git a/ppapi/proxy/serialized_var.cc b/ppapi/proxy/serialized_var.cc
index 1217a83..72e7cc8 100644
--- a/ppapi/proxy/serialized_var.cc
+++ b/ppapi/proxy/serialized_var.cc
@@ -18,13 +18,20 @@
namespace ppapi {
namespace proxy {
+namespace {
+void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) {
+ IPC::ParamTraits<SerializedHandle>::Write(m, handle);
+}
+} // namespace
+
// SerializedVar::Inner --------------------------------------------------------
SerializedVar::Inner::Inner()
: serialization_rules_(NULL),
var_(PP_MakeUndefined()),
instance_(0),
- cleanup_mode_(CLEANUP_NONE) {
+ cleanup_mode_(CLEANUP_NONE),
+ is_valid_var_(true) {
#ifndef NDEBUG
has_been_serialized_ = false;
has_been_deserialized_ = false;
@@ -107,7 +114,24 @@ void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const {
DCHECK(!has_been_serialized_);
has_been_serialized_ = true;
#endif
- RawVarDataGraph::Create(var_, instance_)->Write(m);
+ scoped_ptr<RawVarDataGraph> data = RawVarDataGraph::Create(var_, instance_);
+ if (data) {
+ m->WriteBool(true); // Success.
+ data->Write(m, base::Bind(&DefaultHandleWriter));
+ } else {
+ m->WriteBool(false); // Failure.
+ }
+}
+
+void SerializedVar::Inner::WriteDataToMessage(
+ IPC::Message* m,
+ const HandleWriter& handle_writer) const {
+ if (raw_var_data_) {
+ m->WriteBool(true); // Success.
+ raw_var_data_->Write(m, handle_writer);
+ } else {
+ m->WriteBool(false); // Failure.
+ }
}
bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m,
@@ -125,8 +149,15 @@ bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m,
#endif
// When reading, the dispatcher should be set when we get a Deserialize
// call (which will supply a dispatcher).
- raw_var_data_ = RawVarDataGraph::Read(m, iter);
- return raw_var_data_.get() != NULL;
+ if (!m->ReadBool(iter, &is_valid_var_))
+ return false;
+ if (is_valid_var_) {
+ raw_var_data_ = RawVarDataGraph::Read(m, iter);
+ if (!raw_var_data_)
+ return false;
+ }
+
+ return true;
}
void SerializedVar::Inner::SetCleanupModeToEndSendPassRef() {
diff --git a/ppapi/proxy/serialized_var.h b/ppapi/proxy/serialized_var.h
index 98cafa0..0b8e796 100644
--- a/ppapi/proxy/serialized_var.h
+++ b/ppapi/proxy/serialized_var.h
@@ -80,12 +80,24 @@ class PPAPI_PROXY_EXPORT SerializedVar {
void WriteToMessage(IPC::Message* m) const {
inner_->WriteToMessage(m);
}
+ // If ReadFromMessage has been called, WriteDataToMessage will write the var
+ // that has been read from ReadFromMessage back to a message. This is used
+ // when converting handles for use in NaCl.
+ void WriteDataToMessage(IPC::Message* m,
+ const HandleWriter& handle_writer) const {
+ inner_->WriteDataToMessage(m, handle_writer);
+ }
bool ReadFromMessage(const IPC::Message* m, PickleIterator* iter) {
return inner_->ReadFromMessage(m, iter);
}
- RawVarDataGraph* raw_var_data() const {
- return inner_->raw_var_data();
+ bool is_valid_var() const {
+ return inner_->is_valid_var();
+ }
+
+ // Returns the shared memory handles associated with this SerializedVar.
+ std::vector<SerializedHandle*> GetHandles() const {
+ return inner_->GetHandles();
}
protected:
@@ -110,8 +122,13 @@ class PPAPI_PROXY_EXPORT SerializedVar {
serialization_rules_ = serialization_rules;
}
- RawVarDataGraph* raw_var_data() {
- return raw_var_data_.get();
+ bool is_valid_var() const {
+ return is_valid_var_;
+ }
+
+ std::vector<SerializedHandle*> GetHandles() {
+ return (raw_var_data_ ? raw_var_data_->GetHandles() :
+ std::vector<SerializedHandle*>());
}
// See outer class's declarations above.
@@ -124,6 +141,8 @@ class PPAPI_PROXY_EXPORT SerializedVar {
void ForceSetVarValueForTest(PP_Var value);
void WriteToMessage(IPC::Message* m) const;
+ void WriteDataToMessage(IPC::Message* m,
+ const HandleWriter& handle_writer) const;
bool ReadFromMessage(const IPC::Message* m, PickleIterator* iter);
// Sets the cleanup mode. See the CleanupMode enum below.
@@ -162,6 +181,9 @@ class PPAPI_PROXY_EXPORT SerializedVar {
CleanupMode cleanup_mode_;
+ // If the var is not properly serialized, this will be false.
+ bool is_valid_var_;
+
#ifndef NDEBUG
// When being sent or received over IPC, we should only be serialized or
// deserialized once. These flags help us assert this is true.
@@ -342,6 +364,7 @@ class PPAPI_PROXY_EXPORT SerializedVarReceiveInput {
PP_Var Get(Dispatcher* dispatcher);
PP_Var GetForInstance(Dispatcher* dispatcher, PP_Instance instance);
+ bool is_valid_var() { return serialized_.is_valid_var(); }
private:
const SerializedVar& serialized_;
diff --git a/ppapi/tests/test_post_message.cc b/ppapi/tests/test_post_message.cc
index 8c67ee5..944b5614 100644
--- a/ppapi/tests/test_post_message.cc
+++ b/ppapi/tests/test_post_message.cc
@@ -238,6 +238,16 @@ bool TestPostMessage::AddEchoingListener(const std::string& expression) {
return true;
}
+bool TestPostMessage::PostMessageFromJavaScript(const std::string& func) {
+ std::string js_code;
+ js_code += "var plugin = document.getElementById('plugin');"
+ "plugin.postMessage(";
+ js_code += func + "()";
+ js_code += " );";
+ instance_->EvalScript(js_code);
+ return true;
+}
+
bool TestPostMessage::ClearListeners() {
std::string js_code;
js_code += "var plugin = document.getElementById('plugin');"
@@ -523,6 +533,7 @@ std::string TestPostMessage::TestSendingComplexVar() {
// if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
// should start with these.
WaitForMessages();
+ message_data_.clear();
ASSERT_TRUE(ClearListeners());
pp::Var string(kTestString);
@@ -531,7 +542,6 @@ std::string TestPostMessage::TestSendingComplexVar() {
dictionary.Set(pp::Var("bar"), string);
dictionary.Set(pp::Var("abc"), pp::Var(kTestInt));
dictionary.Set(pp::Var("def"), pp::Var());
- dictionary.Set(pp::Var("dictionary"), dictionary); // Self-reference.
// Reference to array.
pp::VarArray_Dev array;
@@ -544,15 +554,9 @@ std::string TestPostMessage::TestSendingComplexVar() {
dictionary.Set(pp::Var("array-ref1"), array);
dictionary.Set(pp::Var("array-ref2"), array);
- // Set up a (dictionary -> array -> dictionary) cycle.
- pp::VarArray_Dev array2;
- array2.Set(0, dictionary);
- dictionary.Set(pp::Var("array2"), array2);
-
// Set up the JavaScript message event listener to echo the data part of the
// message event back to us.
ASSERT_TRUE(AddEchoingListener("message_event.data"));
- message_data_.clear();
instance_->PostMessage(dictionary);
// PostMessage is asynchronous, so we should not receive a response yet.
ASSERT_EQ(message_data_.size(), 0);
@@ -561,12 +565,36 @@ std::string TestPostMessage::TestSendingComplexVar() {
pp::VarDictionary_Dev result(message_data_.back());
ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
+ WaitForMessages();
+ message_data_.clear();
+ ASSERT_TRUE(ClearListeners());
+
+ // Set up a (dictionary -> array -> dictionary) cycle. Cycles shouldn't be
+ // transmitted.
+ pp::VarArray_Dev array2;
+ array2.Set(0, dictionary);
+ dictionary.Set(pp::Var("array2"), array2);
+
+ ASSERT_TRUE(AddEchoingListener("message_event.data"));
+ instance_->PostMessage(dictionary);
+ // PostMessage is asynchronous, so we should not receive a response yet.
+ ASSERT_EQ(message_data_.size(), 0);
+ ASSERT_EQ(WaitForMessages(), 0);
+
// Break the cycles.
- dictionary.Delete(pp::Var("dictionary"));
dictionary.Delete(pp::Var("array2"));
- result.Delete(pp::Var("dictionary"));
- result.Delete(pp::Var("array2"));
+ WaitForMessages();
+ message_data_.clear();
+ ASSERT_TRUE(ClearListeners());
+
+ // Test sending a cycle from JavaScript to the plugin.
+ ASSERT_TRUE(AddEchoingListener("message_event.data"));
+ PostMessageFromJavaScript("function() { var x = []; x[0] = x; return x; }");
+ ASSERT_EQ(message_data_.size(), 0);
+ ASSERT_EQ(WaitForMessages(), 0);
+
+ WaitForMessages();
message_data_.clear();
ASSERT_TRUE(ClearListeners());
diff --git a/ppapi/tests/test_post_message.h b/ppapi/tests/test_post_message.h
index 3ea69e8..2f2f628 100644
--- a/ppapi/tests/test_post_message.h
+++ b/ppapi/tests/test_post_message.h
@@ -34,6 +34,10 @@ class TestPostMessage : public TestCase {
// Returns true on success, false on failure.
bool AddEchoingListener(const std::string& expression);
+ // Posts a message from JavaScript to the plugin. |func| should be a
+ // JavaScript function which returns the variable to post.
+ bool PostMessageFromJavaScript(const std::string& func);
+
// Clear any listeners that have been added using AddEchoingListener by
// calling removeEventListener for each.
// Returns true on success, false on failure.