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       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 }
    461