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