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/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 }
    462