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