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