- add sources.
[platform/framework/web/crosswalk.git] / src / ppapi / tests / test_url_request.cc
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 // Tests PPB_URLRequestInfo interface.
6
7 #include "ppapi/tests/test_url_request.h"
8
9 #include <string.h>
10 #include <string>
11
12 #include "ppapi/c/dev/ppb_testing_dev.h"
13 #include "ppapi/c/ppb_file_io.h"
14 #include "ppapi/cpp/completion_callback.h"
15 #include "ppapi/cpp/file_io.h"
16 #include "ppapi/cpp/file_ref.h"
17 #include "ppapi/cpp/file_system.h"
18 #include "ppapi/cpp/instance.h"
19 #include "ppapi/cpp/var.h"
20 #include "ppapi/tests/test_utils.h"
21 #include "ppapi/tests/testing_instance.h"
22
23 REGISTER_TEST_CASE(URLRequest);
24
25 namespace {
26 // TODO(polina): move these to test_case.h/cc since other NaCl tests use them?
27
28 const PP_Resource kInvalidResource = 0;
29 const PP_Instance kInvalidInstance = 0;
30
31 // These should not exist.
32 // The bottom 2 bits are used to differentiate between different id types.
33 // 00 - module, 01 - instance, 10 - resource, 11 - var.
34 const PP_Instance kNotAnInstance = 0xFFFFF0;
35 const PP_Resource kNotAResource = 0xAAAAA0;
36 }
37
38 TestURLRequest::TestURLRequest(TestingInstance* instance)
39     : TestCase(instance),
40       ppb_url_request_interface_(NULL),
41       ppb_url_loader_interface_(NULL),
42       ppb_url_response_interface_(NULL),
43       ppb_core_interface_(NULL),
44       ppb_var_interface_(NULL),
45       url_loader_(kInvalidResource) {
46 }
47
48 bool TestURLRequest::Init() {
49   ppb_url_request_interface_ = static_cast<const PPB_URLRequestInfo*>(
50       pp::Module::Get()->GetBrowserInterface(PPB_URLREQUESTINFO_INTERFACE));
51   ppb_url_loader_interface_ = static_cast<const PPB_URLLoader*>(
52       pp::Module::Get()->GetBrowserInterface(PPB_URLLOADER_INTERFACE));
53   ppb_url_response_interface_ = static_cast<const PPB_URLResponseInfo*>(
54       pp::Module::Get()->GetBrowserInterface(PPB_URLRESPONSEINFO_INTERFACE));
55   ppb_core_interface_ = static_cast<const PPB_Core*>(
56       pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
57   ppb_var_interface_ = static_cast<const PPB_Var*>(
58       pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE));
59   if (!ppb_url_request_interface_)
60     instance_->AppendError("PPB_URLRequestInfo interface not available");
61   if (!ppb_url_response_interface_)
62     instance_->AppendError("PPB_URLResponseInfo interface not available");
63   if (!ppb_core_interface_)
64     instance_->AppendError("PPB_Core interface not available");
65   if (!ppb_var_interface_)
66     instance_->AppendError("PPB_Var interface not available");
67   if (!ppb_url_loader_interface_) {
68     instance_->AppendError("PPB_URLLoader interface not available");
69   } else {
70     url_loader_ = ppb_url_loader_interface_->Create(instance_->pp_instance());
71     if (url_loader_ == kInvalidResource)
72       instance_->AppendError("Failed to create URLLoader");
73   }
74   return EnsureRunningOverHTTP();
75 }
76
77 void TestURLRequest::RunTests(const std::string& filter) {
78   RUN_TEST(CreateAndIsURLRequestInfo, filter);
79   RUN_TEST(SetProperty, filter);
80   RUN_TEST(AppendDataToBody, filter);
81   RUN_TEST(AppendFileToBody, filter);
82   RUN_TEST(Stress, filter);
83 }
84
85 PP_Var TestURLRequest::PP_MakeString(const char* s) {
86   return ppb_var_interface_->VarFromUtf8(s, strlen(s));
87 }
88
89 // Tests
90 //   PP_Resource Create(PP_Instance instance)
91 //   PP_Bool IsURLRequestInfo(PP_Resource resource)
92 std::string TestURLRequest::TestCreateAndIsURLRequestInfo() {
93   // Create: Invalid / non-existent instance -> invalid resource.
94   ASSERT_EQ(ppb_url_request_interface_->Create(kInvalidInstance),
95             kInvalidResource);
96   ASSERT_EQ(ppb_url_request_interface_->Create(kNotAnInstance),
97             kInvalidResource);
98
99   // Create: Valid instance -> valid resource.
100   PP_Resource url_request = ppb_url_request_interface_->Create(
101       instance_->pp_instance());
102   ASSERT_NE(url_request, kInvalidResource);
103
104   // IsURLRequestInfo:
105   // Invalid / non-existent / non-URLRequestInfo resource -> false.
106   ASSERT_NE(PP_TRUE,
107             ppb_url_request_interface_->IsURLRequestInfo(kInvalidResource));
108   ASSERT_NE(PP_TRUE,
109             ppb_url_request_interface_->IsURLRequestInfo(kNotAResource));
110   ASSERT_NE(PP_TRUE, ppb_url_request_interface_->IsURLRequestInfo(url_loader_));
111
112   // IsURLRequestInfo: Current URLRequestInfo resource -> true.
113   std::string error;
114   if (PP_FALSE == ppb_url_request_interface_->IsURLRequestInfo(url_request))
115     error = "IsURLRequestInfo() failed with a current URLRequestInfo resource";
116
117   // IsURLRequestInfo: Released URLRequestInfo resource -> false.
118   ppb_core_interface_->ReleaseResource(url_request);
119   ASSERT_NE(PP_TRUE, ppb_url_request_interface_->IsURLRequestInfo(url_request));
120
121   return error;  // == PASS() if empty.
122 }
123
124 // Tests
125 //  PP_Bool SetProperty(PP_Resource request,
126 //                      PP_URLRequestProperty property,
127 //                      struct PP_Var value);
128 std::string TestURLRequest::TestSetProperty() {
129   struct PropertyTestData {
130     PropertyTestData(PP_URLRequestProperty prop,
131                      const std::string& name,
132                      PP_Var value, PP_Bool expected) :
133         property(prop), property_name(name),
134         var(value), expected_value(expected) {
135       // var has ref count of 1 on creation.
136     }
137     PP_URLRequestProperty property;
138     std::string property_name;
139     PP_Var var;  // Instance owner is responsible for releasing this var.
140     PP_Bool expected_value;
141   };
142
143   // All bool properties should accept PP_TRUE and PP_FALSE, while rejecting
144   // all other variable types.
145 #define TEST_BOOL(_name)                                              \
146     PropertyTestData(ID_STR(_name), PP_MakeBool(PP_TRUE), PP_TRUE),   \
147     PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_TRUE),  \
148     PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE),    \
149     PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE),         \
150     PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE),       \
151     PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
152
153   // These property types are always invalid for string properties.
154 #define TEST_STRING_INVALID(_name)                                    \
155     PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE),         \
156     PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \
157     PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE),       \
158     PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
159
160 #define TEST_INT_INVALID(_name)                                         \
161     PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE),      \
162     PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE),           \
163     PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE),   \
164     PropertyTestData(ID_STR(_name), PP_MakeString("notint"), PP_FALSE), \
165     PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE)
166
167   // SetProperty accepts plenty of invalid values (malformed urls, negative
168   // thresholds, etc). Error checking is delayed until request opening (aka url
169   // loading).
170 #define ID_STR(arg) arg, #arg
171     PropertyTestData test_data[] = {
172       TEST_BOOL(PP_URLREQUESTPROPERTY_STREAMTOFILE),
173       TEST_BOOL(PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS),
174       TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS),
175       TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS),
176       TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS),
177       TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS),
178       TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_URL),
179       TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_METHOD),
180       TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_HEADERS),
181       TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL),
182       TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING),
183       TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT),
184       TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD),
185       TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD),
186       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL),
187                        PP_MakeString("http://www.google.com"), PP_TRUE),
188       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL),
189                        PP_MakeString("foo.jpg"), PP_TRUE),
190       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD),
191                        PP_MakeString("GET"), PP_TRUE),
192       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD),
193                        PP_MakeString("POST"), PP_TRUE),
194       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS),
195                        PP_MakeString("Accept: text/plain"), PP_TRUE),
196       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS),
197                        PP_MakeString(""), PP_TRUE),
198       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL),
199                        PP_MakeString("http://www.google.com"), PP_TRUE),
200       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL),
201                        PP_MakeString(""), PP_TRUE),
202       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL),
203                        PP_MakeUndefined(), PP_TRUE),
204       PropertyTestData(
205           ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING),
206           PP_MakeString("base64"), PP_TRUE),
207       PropertyTestData(
208           ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING),
209           PP_MakeString(""), PP_TRUE),
210       PropertyTestData(
211           ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING),
212           PP_MakeUndefined(), PP_TRUE),
213       PropertyTestData(
214           ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT),
215           PP_MakeString("My Crazy Plugin"), PP_TRUE),
216       PropertyTestData(
217           ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT),
218           PP_MakeString(""), PP_TRUE),
219       PropertyTestData(
220           ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT),
221           PP_MakeUndefined(), PP_TRUE),
222       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL),
223                        PP_MakeUndefined(), PP_FALSE),
224       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD),
225                        PP_MakeUndefined(), PP_FALSE),
226       PropertyTestData(
227           ID_STR(PP_URLREQUESTPROPERTY_HEADERS),
228           PP_MakeString("Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA=="),
229           PP_TRUE),
230       PropertyTestData(
231           ID_STR(PP_URLREQUESTPROPERTY_HEADERS),
232           PP_MakeString("Accept-Encoding: *\n"
233                         "Accept-Charset: iso-8859-5, unicode-1-1;q=0.8"),
234           PP_TRUE),
235       PropertyTestData(
236           ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD),
237           PP_MakeInt32(0), PP_TRUE),
238       PropertyTestData(
239           ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD),
240           PP_MakeInt32(100), PP_TRUE),
241       PropertyTestData(
242           ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD),
243           PP_MakeInt32(0), PP_TRUE),
244       PropertyTestData(
245           ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD),
246           PP_MakeInt32(100), PP_TRUE),
247       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL),
248                        PP_MakeString("::::::::::::"), PP_TRUE),
249       PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD),
250           PP_MakeString("INVALID"), PP_TRUE),
251       PropertyTestData(
252           ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING),
253           PP_MakeString("invalid"), PP_TRUE),
254       PropertyTestData(
255           ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD),
256           PP_MakeInt32(-100), PP_TRUE),
257       PropertyTestData(
258           ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD),
259           PP_MakeInt32(-100), PP_TRUE),
260
261     };
262   std::string error;
263
264   PP_Resource url_request = ppb_url_request_interface_->Create(
265       instance_->pp_instance());
266   if (url_request == kInvalidResource)
267     error = "Failed to create a URLRequestInfo";
268
269   // Loop over all test data even if we encountered an error to release vars.
270   for (size_t i = 0;
271        i < sizeof(test_data) / sizeof(test_data[0]);
272        ++i) {
273     if (error.empty() && test_data[i].expected_value !=
274         ppb_url_request_interface_->SetProperty(url_request,
275                                                 test_data[i].property,
276                                                 test_data[i].var)) {
277       pp::Var var(pp::Var::DontManage(), test_data[i].var);
278       error = std::string("Setting property ") +
279           test_data[i].property_name + " to " + var.DebugString() +
280           " did not return " + (test_data[i].expected_value ? "True" : "False");
281       error = test_data[i].property_name;
282     }
283     ppb_var_interface_->Release(test_data[i].var);
284   }
285
286   ppb_core_interface_->ReleaseResource(url_request);
287   return error;  // == PASS() if empty.
288 }
289
290 std::string TestURLRequest::LoadAndCompareBody(
291     PP_Resource url_request, const std::string& expected_body) {
292   TestCompletionCallback callback(instance_->pp_instance(), PP_REQUIRED);
293   callback.WaitForResult(ppb_url_loader_interface_->Open(
294       url_loader_, url_request,
295       callback.GetCallback().pp_completion_callback()));
296   CHECK_CALLBACK_BEHAVIOR(callback);
297   ASSERT_EQ(PP_OK, callback.result());
298
299   std::string error;
300   PP_Resource url_response =
301       ppb_url_loader_interface_->GetResponseInfo(url_loader_);
302   if (url_response == kInvalidResource) {
303     error = "PPB_URLLoader::GetResponseInfo() returned invalid resource";
304   } else {
305     PP_Var status = ppb_url_response_interface_->GetProperty(
306         url_response, PP_URLRESPONSEPROPERTY_STATUSCODE);
307     if (status.type != PP_VARTYPE_INT32 && status.value.as_int != 200)
308       error = ReportError("PPB_URLLoader::Open() status", status.value.as_int);
309
310     std::string actual_body;
311     for (; error.empty();) {  // Read the entire body in this loop.
312       const size_t kBufferSize = 32;
313       char buf[kBufferSize];
314       callback.WaitForResult(ppb_url_loader_interface_->ReadResponseBody(
315           url_loader_, buf, kBufferSize,
316           callback.GetCallback().pp_completion_callback()));
317       if (callback.failed())
318         error.assign(callback.errors());
319       else if (callback.result() < PP_OK)
320         error.assign(ReportError("PPB_URLLoader::ReadResponseBody()",
321                                  callback.result()));
322       if (callback.result() <= PP_OK || callback.failed())
323         break;
324       actual_body.append(buf, callback.result());
325     }
326     if (actual_body != expected_body)
327       error = "PPB_URLLoader::ReadResponseBody() read unexpected response.";
328   }
329   ppb_core_interface_->ReleaseResource(url_response);
330
331   ppb_url_loader_interface_->Close(url_loader_);
332   return error;
333 }
334
335 // Tests
336 //   PP_Bool AppendDataToBody(
337 //       PP_Resource request, const void* data, uint32_t len);
338 std::string TestURLRequest::TestAppendDataToBody() {
339   PP_Resource url_request = ppb_url_request_interface_->Create(
340       instance_->pp_instance());
341   ASSERT_NE(url_request, kInvalidResource);
342
343   std::string postdata("sample postdata");
344   PP_Var post_string_var = PP_MakeString("POST");
345   PP_Var echo_string_var = PP_MakeString("/echo");
346
347   // NULL pointer causes a crash. In general PPAPI implementation does not
348   // test for NULL because they are just a special case of bad pointers that
349   // are not detectable if set to point to an object that does not exist.
350
351   // Invalid resource should fail.
352   ASSERT_EQ(PP_FALSE, ppb_url_request_interface_->AppendDataToBody(
353       kInvalidResource, postdata.data(), postdata.length()));
354
355   // Append data and POST to echoing web server.
356   ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty(
357       url_request, PP_URLREQUESTPROPERTY_METHOD, post_string_var));
358   ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty(
359       url_request, PP_URLREQUESTPROPERTY_URL, echo_string_var));
360
361   // Append data to body and verify the body is what we expect.
362   ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->AppendDataToBody(
363       url_request, postdata.data(), postdata.length()));
364   std::string error = LoadAndCompareBody(url_request, postdata);
365
366   ppb_var_interface_->Release(post_string_var);
367   ppb_var_interface_->Release(echo_string_var);
368   ppb_core_interface_->ReleaseResource(url_request);
369   return error;  // == PASS() if empty.
370 }
371
372 std::string TestURLRequest::TestAppendFileToBody() {
373   PP_Resource url_request = ppb_url_request_interface_->Create(
374       instance_->pp_instance());
375   ASSERT_NE(url_request, kInvalidResource);
376
377   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
378
379   pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
380   callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
381   CHECK_CALLBACK_BEHAVIOR(callback);
382   ASSERT_EQ(PP_OK, callback.result());
383
384   pp::FileRef ref(file_system, "/test_file");
385   pp::FileIO io(instance_);
386   callback.WaitForResult(io.Open(ref,
387                                  PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE,
388                                  callback.GetCallback()));
389   CHECK_CALLBACK_BEHAVIOR(callback);
390   ASSERT_EQ(PP_OK, callback.result());
391
392   std::string append_data = "hello\n";
393   callback.WaitForResult(io.Write(0,
394                                   append_data.c_str(),
395                                   append_data.size(),
396                                   callback.GetCallback()));
397   CHECK_CALLBACK_BEHAVIOR(callback);
398   ASSERT_EQ(static_cast<int32_t>(append_data.size()), callback.result());
399
400   PP_Var post_string_var = PP_MakeString("POST");
401   PP_Var echo_string_var = PP_MakeString("/echo");
402
403   // NULL pointer causes a crash. In general PPAPI implementation does not
404   // test for NULL because they are just a special case of bad pointers that
405   // are not detectable if set to point to an object that does not exist.
406
407   // Invalid resource should fail.
408   ASSERT_EQ(PP_FALSE, ppb_url_request_interface_->AppendFileToBody(
409       kInvalidResource, ref.pp_resource(), 0, -1, 0));
410
411   // Append data and POST to echoing web server.
412   ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty(
413       url_request, PP_URLREQUESTPROPERTY_METHOD, post_string_var));
414   ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty(
415       url_request, PP_URLREQUESTPROPERTY_URL, echo_string_var));
416
417   // Append file to body and verify the body is what we expect.
418   ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->AppendFileToBody(
419       url_request, ref.pp_resource(), 0, -1, 0));
420   std::string error = LoadAndCompareBody(url_request, append_data);
421
422   ppb_var_interface_->Release(post_string_var);
423   ppb_var_interface_->Release(echo_string_var);
424   ppb_core_interface_->ReleaseResource(url_request);
425   return error;  // == PASS() if empty.
426 }
427
428 // Allocates and manipulates a large number of resources.
429 std::string TestURLRequest::TestStress() {
430   const int kManyResources = 500;
431   PP_Resource url_request_info[kManyResources];
432
433   std::string error;
434   int num_created = kManyResources;
435   for (int i = 0; i < kManyResources; i++) {
436     url_request_info[i] = ppb_url_request_interface_->Create(
437         instance_->pp_instance());
438     if (url_request_info[i] == kInvalidResource) {
439       error = "Create() failed";
440     } else if (PP_FALSE == ppb_url_request_interface_->IsURLRequestInfo(
441         url_request_info[i])) {
442       error = "IsURLRequestInfo() failed";
443     } else if (PP_FALSE == ppb_url_request_interface_->SetProperty(
444         url_request_info[i],
445         PP_URLREQUESTPROPERTY_STREAMTOFILE,
446         PP_MakeBool(PP_FALSE))) {
447       error = "SetProperty() failed";
448     }
449     if (!error.empty()) {
450       num_created = i + 1;
451       break;
452     }
453   }
454   for (int i = 0; i < num_created; i++) {
455     ppb_core_interface_->ReleaseResource(url_request_info[i]);
456     if (PP_TRUE ==
457         ppb_url_request_interface_->IsURLRequestInfo(url_request_info[i]))
458       error = "IsURLREquestInfo() succeeded after release";
459   }
460   return error;  // == PASS() if empty.
461 }