1 // Copyright (c) 2012 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.
5 #include "ppapi/tests/test_broker.h"
21 #include "ppapi/c/pp_errors.h"
22 #include "ppapi/c/trusted/ppp_broker.h"
23 #include "ppapi/c/trusted/ppb_broker_trusted.h"
24 #include "ppapi/tests/test_utils.h"
25 #include "ppapi/tests/testing_instance.h"
27 REGISTER_TEST_CASE(Broker
);
31 const char kHelloMessage
[] = "Hello Plugin! This is Broker!";
32 // Message sent from broker to plugin if the broker is unsandboxed.
33 const char kBrokerUnsandboxed
[] = "Broker is Unsandboxed!";
34 // Message sent from broker to plugin if the broker is sandboxed. This message
35 // needs to be longer than |kBrokerUnsandboxed| because the plugin is expecting
36 // |kBrokerUnsandboxed|. If it's shorter and the broker doesn't close its handle
37 // properly the plugin will hang waiting for all data of |kBrokerUnsandboxed| to
39 const char kBrokerSandboxed
[] = "Broker is Sandboxed! Verification failed!";
42 typedef HANDLE PlatformFile
;
43 const PlatformFile kInvalidPlatformFileValue
= INVALID_HANDLE_VALUE
;
44 const int32_t kInvalidHandle
= static_cast<int32_t>(
45 reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE
));
46 #elif defined(OS_POSIX)
47 typedef int PlatformFile
;
48 const PlatformFile kInvalidPlatformFileValue
= -1;
49 const int32_t kInvalidHandle
= -1;
52 PlatformFile
IntToPlatformFile(int32_t handle
) {
54 return reinterpret_cast<HANDLE
>(static_cast<intptr_t>(handle
));
55 #elif defined(OS_POSIX)
61 #define HANDLE_EINTR(x) ({ \
62 typeof(x) __eintr_result__; \
64 __eintr_result__ = x; \
65 } while (__eintr_result__ == -1 && errno == EINTR); \
70 bool ReadMessage(PlatformFile file
, size_t message_len
, char* message
) {
72 assert(message_len
< std::numeric_limits
<DWORD
>::max());
74 const DWORD size
= static_cast<DWORD
>(message_len
);
75 return ::ReadFile(file
, message
, size
, &read
, NULL
) && read
== size
;
76 #elif defined(OS_POSIX)
78 static_cast<size_t>(std::numeric_limits
<ssize_t
>::max()));
79 size_t total_read
= 0;
80 while (total_read
< message_len
) {
81 ssize_t read
= HANDLE_EINTR(::read(file
, message
+ total_read
,
82 message_len
- total_read
));
87 return total_read
== message_len
;
91 bool WriteMessage(PlatformFile file
, size_t message_len
, const char* message
) {
93 assert(message_len
< std::numeric_limits
<DWORD
>::max());
95 const DWORD size
= static_cast<DWORD
>(message_len
);
96 return ::WriteFile(file
, message
, size
, &written
, NULL
) && written
== size
;
97 #elif defined(OS_POSIX)
99 static_cast<size_t>(std::numeric_limits
<ssize_t
>::max()));
100 size_t total_written
= 0;
101 while (total_written
< message_len
) {
102 ssize_t written
= HANDLE_EINTR(::write(file
, message
+ total_written
,
103 message_len
- total_written
));
106 total_written
+= written
;
108 return total_written
== message_len
;
112 bool VerifyMessage(PlatformFile file
, size_t message_len
, const char* message
) {
113 char* message_received
= new char[message_len
];
114 bool success
= ReadMessage(file
, message_len
, message_received
) &&
115 !::strcmp(message_received
, message
);
116 delete [] message_received
;
120 bool ClosePlatformFile(PlatformFile file
) {
122 return !!::CloseHandle(file
);
123 #elif defined(OS_POSIX)
124 return !HANDLE_EINTR(::close(file
));
128 bool VerifyIsUnsandboxed() {
131 wchar_t temp_path
[MAX_PATH
] = {'\0'};
132 wchar_t file_name
[MAX_PATH
] = {'\0'};
133 if (!::GetTempPath(MAX_PATH
, temp_path
) ||
134 !::GetTempFileName(temp_path
, L
"test_pepper_broker", 0, file_name
) ||
135 ::_wfopen_s(&file
, file_name
, L
"w"))
138 if (::fclose(file
)) {
139 ::DeleteFile(file_name
);
143 return !!::DeleteFile(file_name
);
144 #elif defined(OS_POSIX)
145 char file_name
[] = "/tmp/test_pepper_broker_XXXXXX";
146 int fd
= ::mkstemp(file_name
);
150 if (HANDLE_EINTR(::close(fd
))) {
155 return !::remove(file_name
);
159 // Callback in the broker when a new broker connection occurs.
160 int32_t OnInstanceConnected(PP_Instance instance
, int32_t handle
) {
161 PlatformFile file
= IntToPlatformFile(handle
);
162 if (file
== kInvalidPlatformFileValue
)
163 return PP_ERROR_FAILED
;
165 // Send hello message.
166 if (!WriteMessage(file
, sizeof(kHelloMessage
), kHelloMessage
)) {
167 ClosePlatformFile(file
);
168 return PP_ERROR_FAILED
;
171 // Verify broker is not sandboxed and send result to plugin over the pipe.
172 if (VerifyIsUnsandboxed()) {
173 if (!WriteMessage(file
, sizeof(kBrokerUnsandboxed
), kBrokerUnsandboxed
)) {
174 ClosePlatformFile(file
);
175 return PP_ERROR_FAILED
;
178 if (!WriteMessage(file
, sizeof(kBrokerSandboxed
), kBrokerSandboxed
)) {
179 ClosePlatformFile(file
);
180 return PP_ERROR_FAILED
;
184 if (!ClosePlatformFile(file
))
185 return PP_ERROR_FAILED
;
192 PP_EXPORT
int32_t PPP_InitializeBroker(
193 PP_ConnectInstance_Func
* connect_instance_func
) {
194 *connect_instance_func
= &OnInstanceConnected
;
198 PP_EXPORT
void PPP_ShutdownBroker() {}
200 TestBroker::TestBroker(TestingInstance
* instance
)
201 : TestCase(instance
),
202 broker_interface_(NULL
) {
205 bool TestBroker::Init() {
206 broker_interface_
= static_cast<const PPB_BrokerTrusted
*>(
207 pp::Module::Get()->GetBrowserInterface(PPB_BROKER_TRUSTED_INTERFACE
));
208 return !!broker_interface_
;
211 void TestBroker::RunTests(const std::string
& filter
) {
212 RUN_TEST(Create
, filter
);
213 RUN_TEST(Create
, filter
);
214 RUN_TEST(GetHandleFailure
, filter
);
215 RUN_TEST_FORCEASYNC_AND_NOT(ConnectFailure
, filter
);
216 RUN_TEST_FORCEASYNC_AND_NOT(ConnectAndPipe
, filter
);
218 // The following tests require special setup, so only run them if they're
219 // explicitly specified by the filter.
220 if (!ShouldRunAllTests(filter
)) {
221 RUN_TEST(ConnectPermissionDenied
, filter
);
222 RUN_TEST(ConnectPermissionGranted
, filter
);
223 RUN_TEST(IsAllowedPermissionDenied
, filter
);
224 RUN_TEST(IsAllowedPermissionGranted
, filter
);
228 std::string
TestBroker::TestCreate() {
229 // Very simplistic test to make sure we can create a broker interface.
230 // TODO(raymes): All of the resources created in this file are leaked. Write
231 // a C++ wrapper for PPB_Broker_Trusted to avoid these leaks.
232 PP_Resource broker
= broker_interface_
->CreateTrusted(
233 instance_
->pp_instance());
236 ASSERT_FALSE(broker_interface_
->IsBrokerTrusted(0));
237 ASSERT_TRUE(broker_interface_
->IsBrokerTrusted(broker
));
242 // Test connection on invalid resource.
243 std::string
TestBroker::TestConnectFailure() {
244 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
245 callback
.WaitForResult(broker_interface_
->Connect(0,
246 callback
.GetCallback().pp_completion_callback()));
247 CHECK_CALLBACK_BEHAVIOR(callback
);
248 ASSERT_EQ(PP_ERROR_BADRESOURCE
, callback
.result());
253 std::string
TestBroker::TestGetHandleFailure() {
254 int32_t handle
= kInvalidHandle
;
256 // Test getting the handle for an invalid resource.
257 ASSERT_EQ(PP_ERROR_BADRESOURCE
, broker_interface_
->GetHandle(0, &handle
));
259 // Connect hasn't been called so this should fail.
260 PP_Resource broker
= broker_interface_
->CreateTrusted(
261 instance_
->pp_instance());
263 ASSERT_EQ(PP_ERROR_FAILED
, broker_interface_
->GetHandle(broker
, &handle
));
268 std::string
TestBroker::TestConnectAndPipe() {
269 PP_Resource broker
= broker_interface_
->CreateTrusted(
270 instance_
->pp_instance());
273 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
274 callback
.WaitForResult(broker_interface_
->Connect(broker
,
275 callback
.GetCallback().pp_completion_callback()));
276 CHECK_CALLBACK_BEHAVIOR(callback
);
277 ASSERT_EQ(PP_OK
, callback
.result());
279 int32_t handle
= kInvalidHandle
;
280 ASSERT_EQ(PP_OK
, broker_interface_
->GetHandle(broker
, &handle
));
281 ASSERT_NE(kInvalidHandle
, handle
);
283 PlatformFile file
= IntToPlatformFile(handle
);
284 ASSERT_TRUE(VerifyMessage(file
, sizeof(kHelloMessage
), kHelloMessage
));
285 ASSERT_TRUE(VerifyMessage(file
, sizeof(kBrokerUnsandboxed
),
286 kBrokerUnsandboxed
));
288 ASSERT_TRUE(ClosePlatformFile(file
));
293 std::string
TestBroker::TestConnectPermissionDenied() {
294 // This assumes that the browser side is set up to deny access to the broker.
295 PP_Resource broker
= broker_interface_
->CreateTrusted(
296 instance_
->pp_instance());
299 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
300 callback
.WaitForResult(broker_interface_
->Connect(broker
,
301 callback
.GetCallback().pp_completion_callback()));
302 CHECK_CALLBACK_BEHAVIOR(callback
);
303 ASSERT_EQ(PP_ERROR_NOACCESS
, callback
.result());
308 std::string
TestBroker::TestConnectPermissionGranted() {
309 // This assumes that the browser side is set up to allow access to the broker.
310 PP_Resource broker
= broker_interface_
->CreateTrusted(
311 instance_
->pp_instance());
314 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
315 callback
.WaitForResult(broker_interface_
->Connect(broker
,
316 callback
.GetCallback().pp_completion_callback()));
317 CHECK_CALLBACK_BEHAVIOR(callback
);
318 ASSERT_EQ(PP_OK
, callback
.result());
323 std::string
TestBroker::TestIsAllowedPermissionDenied() {
324 PP_Resource broker
= broker_interface_
->CreateTrusted(
325 instance_
->pp_instance());
327 ASSERT_EQ(PP_FALSE
, broker_interface_
->IsAllowed(broker
));
332 std::string
TestBroker::TestIsAllowedPermissionGranted() {
333 PP_Resource broker
= broker_interface_
->CreateTrusted(
334 instance_
->pp_instance());
336 ASSERT_EQ(PP_TRUE
, broker_interface_
->IsAllowed(broker
));