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.
4
5 #include "ppapi/tests/test_utils.h"
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #if defined(_MSC_VER)
11 #include <windows.h>
12 #else
13 #include <unistd.h>
14 #endif
15
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/cpp/instance_handle.h"
18 #include "ppapi/cpp/module.h"
19 #include "ppapi/cpp/net_address.h"
20 #include "ppapi/cpp/private/host_resolver_private.h"
21 #include "ppapi/cpp/private/net_address_private.h"
22 #include "ppapi/cpp/url_loader.h"
23 #include "ppapi/cpp/var.h"
24
25 namespace {
26
IsBigEndian()27 bool IsBigEndian() {
28 union {
29 uint32_t integer32;
30 uint8_t integer8[4];
31 } data = { 0x01020304 };
32
33 return data.integer8[0] == 1;
34 }
35
DoNothing(void * user_data,int32_t result)36 void DoNothing(void* user_data, int32_t result) {}
37
38 } // namespace
39
40 const int kActionTimeoutMs = 10000;
41
GetTestingInterface()42 const PPB_Testing_Private* GetTestingInterface() {
43 static const PPB_Testing_Private* g_testing_interface =
44 static_cast<const PPB_Testing_Private*>(
45 pp::Module::Get()->GetBrowserInterface(
46 PPB_TESTING_PRIVATE_INTERFACE));
47 return g_testing_interface;
48 }
49
ReportError(const char * method,int32_t error)50 std::string ReportError(const char* method, int32_t error) {
51 char error_as_string[12];
52 sprintf(error_as_string, "%d", static_cast<int>(error));
53 std::string result = method + std::string(" failed with error: ") +
54 error_as_string;
55 return result;
56 }
57
PlatformSleep(int duration_ms)58 void PlatformSleep(int duration_ms) {
59 #if defined(_MSC_VER)
60 ::Sleep(duration_ms);
61 #else
62 usleep(duration_ms * 1000);
63 #endif
64 }
65
GetLocalHostPort(PP_Instance instance,std::string * host,uint16_t * port)66 bool GetLocalHostPort(PP_Instance instance, std::string* host, uint16_t* port) {
67 if (!host || !port)
68 return false;
69
70 const PPB_Testing_Private* testing = GetTestingInterface();
71 if (!testing)
72 return false;
73
74 PP_URLComponents_Dev components;
75 pp::Var pp_url(pp::PASS_REF,
76 testing->GetDocumentURL(instance, &components));
77 if (!pp_url.is_string())
78 return false;
79 std::string url = pp_url.AsString();
80
81 if (components.host.len < 0)
82 return false;
83 host->assign(url.substr(components.host.begin, components.host.len));
84
85 if (components.port.len <= 0)
86 return false;
87
88 int i = atoi(url.substr(components.port.begin, components.port.len).c_str());
89 if (i < 0 || i > 65535)
90 return false;
91 *port = static_cast<uint16_t>(i);
92
93 return true;
94 }
95
ConvertFromNetEndian16(uint16_t x)96 uint16_t ConvertFromNetEndian16(uint16_t x) {
97 if (IsBigEndian())
98 return x;
99 else
100 return (x << 8) | (x >> 8);
101 }
102
ConvertToNetEndian16(uint16_t x)103 uint16_t ConvertToNetEndian16(uint16_t x) {
104 if (IsBigEndian())
105 return x;
106 else
107 return (x << 8) | (x >> 8);
108 }
109
EqualNetAddress(const pp::NetAddress & addr1,const pp::NetAddress & addr2)110 bool EqualNetAddress(const pp::NetAddress& addr1, const pp::NetAddress& addr2) {
111 if (addr1.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED ||
112 addr2.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED) {
113 return false;
114 }
115
116 if (addr1.GetFamily() == PP_NETADDRESS_FAMILY_IPV4) {
117 PP_NetAddress_IPv4 ipv4_addr1, ipv4_addr2;
118 if (!addr1.DescribeAsIPv4Address(&ipv4_addr1) ||
119 !addr2.DescribeAsIPv4Address(&ipv4_addr2)) {
120 return false;
121 }
122
123 return ipv4_addr1.port == ipv4_addr2.port &&
124 !memcmp(ipv4_addr1.addr, ipv4_addr2.addr, sizeof(ipv4_addr1.addr));
125 } else {
126 PP_NetAddress_IPv6 ipv6_addr1, ipv6_addr2;
127 if (!addr1.DescribeAsIPv6Address(&ipv6_addr1) ||
128 !addr2.DescribeAsIPv6Address(&ipv6_addr2)) {
129 return false;
130 }
131
132 return ipv6_addr1.port == ipv6_addr2.port &&
133 !memcmp(ipv6_addr1.addr, ipv6_addr2.addr, sizeof(ipv6_addr1.addr));
134 }
135 }
136
ResolveHost(PP_Instance instance,const std::string & host,uint16_t port,pp::NetAddress * addr)137 bool ResolveHost(PP_Instance instance,
138 const std::string& host,
139 uint16_t port,
140 pp::NetAddress* addr) {
141 // TODO(yzshen): Change to use the public host resolver once it is supported.
142 pp::InstanceHandle instance_handle(instance);
143 pp::HostResolverPrivate host_resolver(instance_handle);
144 PP_HostResolver_Private_Hint hint =
145 { PP_NETADDRESSFAMILY_PRIVATE_UNSPECIFIED, 0 };
146
147 TestCompletionCallback callback(instance);
148 callback.WaitForResult(
149 host_resolver.Resolve(host, port, hint, callback.GetCallback()));
150
151 PP_NetAddress_Private addr_private;
152 if (callback.result() != PP_OK || host_resolver.GetSize() == 0 ||
153 !host_resolver.GetNetAddress(0, &addr_private)) {
154 return false;
155 }
156
157 switch (pp::NetAddressPrivate::GetFamily(addr_private)) {
158 case PP_NETADDRESSFAMILY_PRIVATE_IPV4: {
159 PP_NetAddress_IPv4 ipv4_addr;
160 ipv4_addr.port = ConvertToNetEndian16(
161 pp::NetAddressPrivate::GetPort(addr_private));
162 if (!pp::NetAddressPrivate::GetAddress(addr_private, ipv4_addr.addr,
163 sizeof(ipv4_addr.addr))) {
164 return false;
165 }
166 *addr = pp::NetAddress(instance_handle, ipv4_addr);
167 return true;
168 }
169 case PP_NETADDRESSFAMILY_PRIVATE_IPV6: {
170 PP_NetAddress_IPv6 ipv6_addr;
171 ipv6_addr.port = ConvertToNetEndian16(
172 pp::NetAddressPrivate::GetPort(addr_private));
173 if (!pp::NetAddressPrivate::GetAddress(addr_private, ipv6_addr.addr,
174 sizeof(ipv6_addr.addr))) {
175 return false;
176 }
177 *addr = pp::NetAddress(instance_handle, ipv6_addr);
178 return true;
179 }
180 default: {
181 return false;
182 }
183 }
184 }
185
ReplacePort(PP_Instance instance,const pp::NetAddress & input_addr,uint16_t port,pp::NetAddress * output_addr)186 bool ReplacePort(PP_Instance instance,
187 const pp::NetAddress& input_addr,
188 uint16_t port,
189 pp::NetAddress* output_addr) {
190 switch (input_addr.GetFamily()) {
191 case PP_NETADDRESS_FAMILY_IPV4: {
192 PP_NetAddress_IPv4 ipv4_addr;
193 if (!input_addr.DescribeAsIPv4Address(&ipv4_addr))
194 return false;
195 ipv4_addr.port = ConvertToNetEndian16(port);
196 *output_addr = pp::NetAddress(pp::InstanceHandle(instance), ipv4_addr);
197 return true;
198 }
199 case PP_NETADDRESS_FAMILY_IPV6: {
200 PP_NetAddress_IPv6 ipv6_addr;
201 if (!input_addr.DescribeAsIPv6Address(&ipv6_addr))
202 return false;
203 ipv6_addr.port = ConvertToNetEndian16(port);
204 *output_addr = pp::NetAddress(pp::InstanceHandle(instance), ipv6_addr);
205 return true;
206 }
207 default: {
208 return false;
209 }
210 }
211 }
212
GetPort(const pp::NetAddress & addr)213 uint16_t GetPort(const pp::NetAddress& addr) {
214 switch (addr.GetFamily()) {
215 case PP_NETADDRESS_FAMILY_IPV4: {
216 PP_NetAddress_IPv4 ipv4_addr;
217 if (!addr.DescribeAsIPv4Address(&ipv4_addr))
218 return 0;
219 return ConvertFromNetEndian16(ipv4_addr.port);
220 }
221 case PP_NETADDRESS_FAMILY_IPV6: {
222 PP_NetAddress_IPv6 ipv6_addr;
223 if (!addr.DescribeAsIPv6Address(&ipv6_addr))
224 return 0;
225 return ConvertFromNetEndian16(ipv6_addr.port);
226 }
227 default: {
228 return 0;
229 }
230 }
231 }
232
Wait()233 void NestedEvent::Wait() {
234 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
235 // Don't allow nesting more than once; it doesn't work with the code as-is,
236 // and probably is a bad idea most of the time anyway.
237 PP_DCHECK(!waiting_);
238 if (signalled_)
239 return;
240 waiting_ = true;
241 while (!signalled_)
242 GetTestingInterface()->RunMessageLoop(instance_);
243 waiting_ = false;
244 }
245
Signal()246 void NestedEvent::Signal() {
247 if (pp::Module::Get()->core()->IsMainThread())
248 SignalOnMainThread();
249 else
250 PostSignal(0);
251 }
252
PostSignal(int32_t wait_ms)253 void NestedEvent::PostSignal(int32_t wait_ms) {
254 pp::Module::Get()->core()->CallOnMainThread(
255 wait_ms,
256 pp::CompletionCallback(&SignalThunk, this),
257 0);
258 }
259
Reset()260 void NestedEvent::Reset() {
261 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
262 // It doesn't make sense to reset when we're still waiting.
263 PP_DCHECK(!waiting_);
264 signalled_ = false;
265 }
266
SignalOnMainThread()267 void NestedEvent::SignalOnMainThread() {
268 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
269 signalled_ = true;
270 if (waiting_)
271 GetTestingInterface()->QuitMessageLoop(instance_);
272 }
273
SignalThunk(void * event,int32_t)274 void NestedEvent::SignalThunk(void* event, int32_t /* result */) {
275 static_cast<NestedEvent*>(event)->SignalOnMainThread();
276 }
277
DoNothingCallback()278 pp::CompletionCallback DoNothingCallback() {
279 return pp::CompletionCallback(&DoNothing, NULL,
280 PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
281 }
282
TestCompletionCallback(PP_Instance instance)283 TestCompletionCallback::TestCompletionCallback(PP_Instance instance)
284 : wait_for_result_called_(false),
285 have_result_(false),
286 result_(PP_OK_COMPLETIONPENDING),
287 // TODO(dmichael): The default should probably be PP_REQUIRED, but this is
288 // what the tests currently expect.
289 callback_type_(PP_OPTIONAL),
290 post_quit_task_(false),
291 instance_(instance),
292 delegate_(NULL) {
293 }
294
TestCompletionCallback(PP_Instance instance,bool force_async)295 TestCompletionCallback::TestCompletionCallback(PP_Instance instance,
296 bool force_async)
297 : wait_for_result_called_(false),
298 have_result_(false),
299 result_(PP_OK_COMPLETIONPENDING),
300 callback_type_(force_async ? PP_REQUIRED : PP_OPTIONAL),
301 post_quit_task_(false),
302 instance_(instance),
303 delegate_(NULL) {
304 }
305
TestCompletionCallback(PP_Instance instance,CallbackType callback_type)306 TestCompletionCallback::TestCompletionCallback(PP_Instance instance,
307 CallbackType callback_type)
308 : wait_for_result_called_(false),
309 have_result_(false),
310 result_(PP_OK_COMPLETIONPENDING),
311 callback_type_(callback_type),
312 post_quit_task_(false),
313 instance_(instance),
314 delegate_(NULL) {
315 }
316
WaitForResult(int32_t result)317 void TestCompletionCallback::WaitForResult(int32_t result) {
318 PP_DCHECK(!wait_for_result_called_);
319 wait_for_result_called_ = true;
320 errors_.clear();
321 if (result == PP_OK_COMPLETIONPENDING) {
322 if (!have_result_) {
323 post_quit_task_ = true;
324 RunMessageLoop();
325 }
326 if (callback_type_ == PP_BLOCKING) {
327 errors_.assign(
328 ReportError("TestCompletionCallback: Call did not run synchronously "
329 "when passed a blocking completion callback!",
330 result_));
331 return;
332 }
333 } else {
334 result_ = result;
335 have_result_ = true;
336 if (callback_type_ == PP_REQUIRED) {
337 errors_.assign(
338 ReportError("TestCompletionCallback: Call ran synchronously when "
339 "passed a required completion callback!",
340 result_));
341 return;
342 }
343 }
344 PP_DCHECK(have_result_ == true);
345 }
346
WaitForAbortResult(int32_t result)347 void TestCompletionCallback::WaitForAbortResult(int32_t result) {
348 WaitForResult(result);
349 int32_t final_result = result_;
350 if (result == PP_OK_COMPLETIONPENDING) {
351 if (final_result != PP_ERROR_ABORTED) {
352 errors_.assign(
353 ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
354 "PP_OK. Ran asynchronously.",
355 final_result));
356 return;
357 }
358 } else if (result < PP_OK) {
359 errors_.assign(
360 ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
361 "non-error response. Ran synchronously.",
362 result));
363 return;
364 }
365 }
366
GetCallback()367 pp::CompletionCallback TestCompletionCallback::GetCallback() {
368 Reset();
369 int32_t flags = 0;
370 if (callback_type_ == PP_BLOCKING)
371 return pp::CompletionCallback();
372 else if (callback_type_ == PP_OPTIONAL)
373 flags = PP_COMPLETIONCALLBACK_FLAG_OPTIONAL;
374 target_loop_ = pp::MessageLoop::GetCurrent();
375 return pp::CompletionCallback(&TestCompletionCallback::Handler,
376 const_cast<TestCompletionCallback*>(this),
377 flags);
378 }
379
Reset()380 void TestCompletionCallback::Reset() {
381 wait_for_result_called_ = false;
382 result_ = PP_OK_COMPLETIONPENDING;
383 have_result_ = false;
384 post_quit_task_ = false;
385 delegate_ = NULL;
386 errors_.clear();
387 }
388
389 // static
Handler(void * user_data,int32_t result)390 void TestCompletionCallback::Handler(void* user_data, int32_t result) {
391 TestCompletionCallback* callback =
392 static_cast<TestCompletionCallback*>(user_data);
393 // If this check fails, it means that the callback was invoked twice or that
394 // the PPAPI call completed synchronously, but also ran the callback.
395 PP_DCHECK(!callback->have_result_);
396 callback->result_ = result;
397 callback->have_result_ = true;
398 if (callback->delegate_)
399 callback->delegate_->OnCallback(user_data, result);
400 if (callback->post_quit_task_) {
401 callback->post_quit_task_ = false;
402 callback->QuitMessageLoop();
403 }
404 if (callback->target_loop_ != pp::MessageLoop::GetCurrent()) {
405 // Note, in-process, loop_ and GetCurrent() will both be NULL, so should
406 // still be equal.
407 callback->errors_.assign(
408 ReportError("TestCompletionCallback: Callback ran on the wrong message "
409 "loop!",
410 result));
411 }
412 }
413
RunMessageLoop()414 void TestCompletionCallback::RunMessageLoop() {
415 pp::MessageLoop loop(pp::MessageLoop::GetCurrent());
416 // If we don't have a message loop, we're probably running in process, where
417 // PPB_MessageLoop is not supported. Just use the Testing message loop.
418 if (loop.is_null() || loop == pp::MessageLoop::GetForMainThread())
419 GetTestingInterface()->RunMessageLoop(instance_);
420 else
421 loop.Run();
422 }
423
QuitMessageLoop()424 void TestCompletionCallback::QuitMessageLoop() {
425 pp::MessageLoop loop(pp::MessageLoop::GetCurrent());
426 // If we don't have a message loop, we're probably running in process, where
427 // PPB_MessageLoop is not supported. Just use the Testing message loop.
428 if (loop.is_null() || loop == pp::MessageLoop::GetForMainThread()) {
429 GetTestingInterface()->QuitMessageLoop(instance_);
430 } else {
431 const bool should_quit = false;
432 loop.PostQuit(should_quit);
433 }
434 }
435
OpenURLRequest(PP_Instance instance,pp::URLLoader * loader,const pp::URLRequestInfo & request,CallbackType callback_type,std::string * response_body)436 int32_t OpenURLRequest(PP_Instance instance,
437 pp::URLLoader* loader,
438 const pp::URLRequestInfo& request,
439 CallbackType callback_type,
440 std::string* response_body) {
441 {
442 TestCompletionCallback open_callback(instance, callback_type);
443 open_callback.WaitForResult(
444 loader->Open(request, open_callback.GetCallback()));
445 if (open_callback.result() != PP_OK)
446 return open_callback.result();
447 }
448
449 int32_t bytes_read = 0;
450 do {
451 char buffer[1024];
452 TestCompletionCallback read_callback(instance, callback_type);
453 read_callback.WaitForResult(loader->ReadResponseBody(
454 &buffer, sizeof(buffer), read_callback.GetCallback()));
455 bytes_read = read_callback.result();
456 if (bytes_read < 0)
457 return bytes_read;
458 if (response_body)
459 response_body->append(std::string(buffer, bytes_read));
460 } while (bytes_read > 0);
461
462 return PP_OK;
463 }
464