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