| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // Tests PPB_URLRequestInfo interface. |
| |
| #include "ppapi/tests/test_url_request.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include <string> |
| |
| #include "ppapi/c/ppb_file_io.h" |
| #include "ppapi/cpp/completion_callback.h" |
| #include "ppapi/cpp/file_io.h" |
| #include "ppapi/cpp/file_ref.h" |
| #include "ppapi/cpp/file_system.h" |
| #include "ppapi/cpp/instance.h" |
| #include "ppapi/cpp/var.h" |
| #include "ppapi/tests/test_utils.h" |
| #include "ppapi/tests/testing_instance.h" |
| |
| REGISTER_TEST_CASE(URLRequest); |
| |
| namespace { |
| // TODO(polina): move these to test_case.h/cc since other NaCl tests use them? |
| |
| const PP_Resource kInvalidResource = 0; |
| const PP_Instance kInvalidInstance = 0; |
| |
| // These should not exist. |
| // The bottom 2 bits are used to differentiate between different id types. |
| // 00 - module, 01 - instance, 10 - resource, 11 - var. |
| const PP_Instance kNotAnInstance = 0xFFFFF0; |
| const PP_Resource kNotAResource = 0xAAAAA0; |
| } |
| |
| TestURLRequest::TestURLRequest(TestingInstance* instance) |
| : TestCase(instance), |
| ppb_url_request_interface_(NULL), |
| ppb_url_loader_interface_(NULL), |
| ppb_url_response_interface_(NULL), |
| ppb_core_interface_(NULL), |
| ppb_var_interface_(NULL) { |
| } |
| |
| bool TestURLRequest::Init() { |
| ppb_url_request_interface_ = static_cast<const PPB_URLRequestInfo*>( |
| pp::Module::Get()->GetBrowserInterface(PPB_URLREQUESTINFO_INTERFACE)); |
| ppb_url_loader_interface_ = static_cast<const PPB_URLLoader*>( |
| pp::Module::Get()->GetBrowserInterface(PPB_URLLOADER_INTERFACE)); |
| ppb_url_response_interface_ = static_cast<const PPB_URLResponseInfo*>( |
| pp::Module::Get()->GetBrowserInterface(PPB_URLRESPONSEINFO_INTERFACE)); |
| ppb_core_interface_ = static_cast<const PPB_Core*>( |
| pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE)); |
| ppb_var_interface_ = static_cast<const PPB_Var*>( |
| pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE)); |
| if (!ppb_url_request_interface_) |
| instance_->AppendError("PPB_URLRequestInfo interface not available"); |
| if (!ppb_url_response_interface_) |
| instance_->AppendError("PPB_URLResponseInfo interface not available"); |
| if (!ppb_core_interface_) |
| instance_->AppendError("PPB_Core interface not available"); |
| if (!ppb_var_interface_) |
| instance_->AppendError("PPB_Var interface not available"); |
| if (!ppb_url_loader_interface_) { |
| instance_->AppendError("PPB_URLLoader interface not available"); |
| } |
| return EnsureRunningOverHTTP(); |
| } |
| |
| void TestURLRequest::RunTests(const std::string& filter) { |
| RUN_TEST(CreateAndIsURLRequestInfo, filter); |
| RUN_TEST(SetProperty, filter); |
| RUN_TEST(AppendDataToBody, filter); |
| RUN_TEST(AppendFileToBody, filter); |
| RUN_TEST(Stress, filter); |
| } |
| |
| PP_Var TestURLRequest::PP_MakeString(const char* s) { |
| return ppb_var_interface_->VarFromUtf8(s, static_cast<int32_t>(strlen(s))); |
| } |
| |
| // Tests |
| // PP_Resource Create(PP_Instance instance) |
| // PP_Bool IsURLRequestInfo(PP_Resource resource) |
| std::string TestURLRequest::TestCreateAndIsURLRequestInfo() { |
| // Create: Invalid / non-existent instance -> invalid resource. |
| ASSERT_EQ(ppb_url_request_interface_->Create(kInvalidInstance), |
| kInvalidResource); |
| ASSERT_EQ(ppb_url_request_interface_->Create(kNotAnInstance), |
| kInvalidResource); |
| |
| // Create: Valid instance -> valid resource. |
| PP_Resource url_request = ppb_url_request_interface_->Create( |
| instance_->pp_instance()); |
| ASSERT_NE(url_request, kInvalidResource); |
| |
| // IsURLRequestInfo: |
| // Invalid / non-existent / non-URLRequestInfo resource -> false. |
| ASSERT_NE(PP_TRUE, |
| ppb_url_request_interface_->IsURLRequestInfo(kInvalidResource)); |
| ASSERT_NE(PP_TRUE, |
| ppb_url_request_interface_->IsURLRequestInfo(kNotAResource)); |
| |
| PP_Resource url_loader = |
| ppb_url_loader_interface_->Create(instance_->pp_instance()); |
| ASSERT_NE(kInvalidResource, url_loader); |
| |
| ASSERT_NE(PP_TRUE, ppb_url_request_interface_->IsURLRequestInfo(url_loader)); |
| ppb_url_loader_interface_->Close(url_loader); |
| ppb_core_interface_->ReleaseResource(url_loader); |
| |
| // IsURLRequestInfo: Current URLRequestInfo resource -> true. |
| std::string error; |
| if (PP_FALSE == ppb_url_request_interface_->IsURLRequestInfo(url_request)) |
| error = "IsURLRequestInfo() failed with a current URLRequestInfo resource"; |
| |
| // IsURLRequestInfo: Released URLRequestInfo resource -> false. |
| ppb_core_interface_->ReleaseResource(url_request); |
| ASSERT_NE(PP_TRUE, ppb_url_request_interface_->IsURLRequestInfo(url_request)); |
| |
| return error; // == PASS() if empty. |
| } |
| |
| // Tests |
| // PP_Bool SetProperty(PP_Resource request, |
| // PP_URLRequestProperty property, |
| // struct PP_Var value); |
| std::string TestURLRequest::TestSetProperty() { |
| struct PropertyTestData { |
| PropertyTestData(PP_URLRequestProperty prop, |
| const std::string& name, |
| PP_Var value, PP_Bool expected) : |
| property(prop), property_name(name), |
| var(value), expected_value(expected) { |
| // var has ref count of 1 on creation. |
| } |
| PP_URLRequestProperty property; |
| std::string property_name; |
| PP_Var var; // Instance owner is responsible for releasing this var. |
| PP_Bool expected_value; |
| }; |
| |
| // All bool properties should accept PP_TRUE and PP_FALSE, while rejecting |
| // all other variable types. |
| #define TEST_BOOL(_name) \ |
| PropertyTestData(ID_STR(_name), PP_MakeBool(PP_TRUE), PP_TRUE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_TRUE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE) |
| |
| // These property types are always invalid for string properties. |
| #define TEST_STRING_INVALID(_name) \ |
| PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeInt32(0), PP_FALSE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE) |
| |
| #define TEST_INT_INVALID(_name) \ |
| PropertyTestData(ID_STR(_name), PP_MakeUndefined(), PP_FALSE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeNull(), PP_FALSE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeBool(PP_FALSE), PP_FALSE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeString("notint"), PP_FALSE), \ |
| PropertyTestData(ID_STR(_name), PP_MakeDouble(0.0), PP_FALSE) |
| |
| // SetProperty accepts plenty of invalid values (malformed urls, negative |
| // thresholds, etc). Error checking is delayed until request opening (aka url |
| // loading). |
| #define ID_STR(arg) arg, #arg |
| PropertyTestData test_data[] = { |
| TEST_BOOL(PP_URLREQUESTPROPERTY_STREAMTOFILE), |
| TEST_BOOL(PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS), |
| TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS), |
| TEST_BOOL(PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS), |
| TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS), |
| TEST_BOOL(PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS), |
| TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_URL), |
| TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_METHOD), |
| TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_HEADERS), |
| TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL), |
| TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING), |
| TEST_STRING_INVALID(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT), |
| TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD), |
| TEST_INT_INVALID(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL), |
| PP_MakeString("http://www.google.com"), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL), |
| PP_MakeString("foo.jpg"), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD), |
| PP_MakeString("GET"), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD), |
| PP_MakeString("POST"), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS), |
| PP_MakeString("Accept: text/plain"), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_HEADERS), |
| PP_MakeString(""), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL), |
| PP_MakeString("http://www.google.com"), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL), |
| PP_MakeString(""), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL), |
| PP_MakeUndefined(), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING), |
| PP_MakeString("base64"), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING), |
| PP_MakeString(""), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING), |
| PP_MakeUndefined(), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT), |
| PP_MakeString("My Crazy Plugin"), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT), |
| PP_MakeString(""), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT), |
| PP_MakeUndefined(), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL), |
| PP_MakeUndefined(), PP_FALSE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD), |
| PP_MakeUndefined(), PP_FALSE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_HEADERS), |
| PP_MakeString("Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA=="), |
| PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_HEADERS), |
| PP_MakeString("Accept-Encoding: *\n" |
| "Accept-Charset: iso-8859-5, unicode-1-1;q=0.8"), |
| PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD), |
| PP_MakeInt32(0), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD), |
| PP_MakeInt32(100), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD), |
| PP_MakeInt32(0), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD), |
| PP_MakeInt32(100), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_URL), |
| PP_MakeString("::::::::::::"), PP_TRUE), |
| PropertyTestData(ID_STR(PP_URLREQUESTPROPERTY_METHOD), |
| PP_MakeString("INVALID"), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING), |
| PP_MakeString("invalid"), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD), |
| PP_MakeInt32(-100), PP_TRUE), |
| PropertyTestData( |
| ID_STR(PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD), |
| PP_MakeInt32(-100), PP_TRUE), |
| |
| }; |
| std::string error; |
| |
| PP_Resource url_request = ppb_url_request_interface_->Create( |
| instance_->pp_instance()); |
| if (url_request == kInvalidResource) |
| error = "Failed to create a URLRequestInfo"; |
| |
| // Loop over all test data even if we encountered an error to release vars. |
| for (size_t i = 0; |
| i < sizeof(test_data) / sizeof(test_data[0]); |
| ++i) { |
| if (error.empty() && test_data[i].expected_value != |
| ppb_url_request_interface_->SetProperty(url_request, |
| test_data[i].property, |
| test_data[i].var)) { |
| pp::Var var(pp::Var::DontManage(), test_data[i].var); |
| error = std::string("Setting property ") + |
| test_data[i].property_name + " to " + var.DebugString() + |
| " did not return " + (test_data[i].expected_value ? "True" : "False"); |
| error = test_data[i].property_name; |
| } |
| ppb_var_interface_->Release(test_data[i].var); |
| } |
| |
| ppb_core_interface_->ReleaseResource(url_request); |
| return error; // == PASS() if empty. |
| } |
| |
| std::string TestURLRequest::LoadAndCompareBody( |
| PP_Resource url_request, const std::string& expected_body) { |
| TestCompletionCallback callback(instance_->pp_instance(), PP_REQUIRED); |
| |
| PP_Resource url_loader = |
| ppb_url_loader_interface_->Create(instance_->pp_instance()); |
| ASSERT_NE(kInvalidResource, url_loader); |
| |
| callback.WaitForResult(ppb_url_loader_interface_->Open( |
| url_loader, url_request, |
| callback.GetCallback().pp_completion_callback())); |
| CHECK_CALLBACK_BEHAVIOR(callback); |
| ASSERT_EQ(PP_OK, callback.result()); |
| |
| std::string error; |
| PP_Resource url_response = |
| ppb_url_loader_interface_->GetResponseInfo(url_loader); |
| if (url_response == kInvalidResource) { |
| error = "PPB_URLLoader::GetResponseInfo() returned invalid resource"; |
| } else { |
| PP_Var status = ppb_url_response_interface_->GetProperty( |
| url_response, PP_URLRESPONSEPROPERTY_STATUSCODE); |
| if (status.type != PP_VARTYPE_INT32 && status.value.as_int != 200) |
| error = ReportError("PPB_URLLoader::Open() status", status.value.as_int); |
| |
| std::string actual_body; |
| for (; error.empty();) { // Read the entire body in this loop. |
| const size_t kBufferSize = 32; |
| char buf[kBufferSize]; |
| callback.WaitForResult(ppb_url_loader_interface_->ReadResponseBody( |
| url_loader, buf, kBufferSize, |
| callback.GetCallback().pp_completion_callback())); |
| if (callback.failed()) |
| error.assign(callback.errors()); |
| else if (callback.result() < PP_OK) |
| error.assign(ReportError("PPB_URLLoader::ReadResponseBody()", |
| callback.result())); |
| if (callback.result() <= PP_OK || callback.failed()) |
| break; |
| actual_body.append(buf, callback.result()); |
| } |
| if (actual_body != expected_body) |
| error = "PPB_URLLoader::ReadResponseBody() read unexpected response."; |
| } |
| ppb_core_interface_->ReleaseResource(url_response); |
| |
| ppb_url_loader_interface_->Close(url_loader); |
| ppb_core_interface_->ReleaseResource(url_loader); |
| return error; |
| } |
| |
| // Tests |
| // PP_Bool AppendDataToBody( |
| // PP_Resource request, const void* data, uint32_t len); |
| std::string TestURLRequest::TestAppendDataToBody() { |
| PP_Resource url_request = ppb_url_request_interface_->Create( |
| instance_->pp_instance()); |
| ASSERT_NE(url_request, kInvalidResource); |
| |
| std::string postdata("sample postdata"); |
| PP_Var post_string_var = PP_MakeString("POST"); |
| PP_Var echo_string_var = PP_MakeString("/echo"); |
| |
| // NULL pointer causes a crash. In general PPAPI implementation does not |
| // test for NULL because they are just a special case of bad pointers that |
| // are not detectable if set to point to an object that does not exist. |
| |
| // Invalid resource should fail. |
| ASSERT_EQ(PP_FALSE, ppb_url_request_interface_->AppendDataToBody( |
| kInvalidResource, postdata.data(), |
| static_cast<uint32_t>(postdata.length()))); |
| |
| // Append data and POST to echoing web server. |
| ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty( |
| url_request, PP_URLREQUESTPROPERTY_METHOD, post_string_var)); |
| ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty( |
| url_request, PP_URLREQUESTPROPERTY_URL, echo_string_var)); |
| |
| // Append data to body and verify the body is what we expect. |
| ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->AppendDataToBody( |
| url_request, postdata.data(), |
| static_cast<uint32_t>(postdata.length()))); |
| std::string error = LoadAndCompareBody(url_request, postdata); |
| |
| ppb_var_interface_->Release(post_string_var); |
| ppb_var_interface_->Release(echo_string_var); |
| ppb_core_interface_->ReleaseResource(url_request); |
| return error; // == PASS() if empty. |
| } |
| |
| std::string TestURLRequest::TestAppendFileToBody() { |
| PP_Resource url_request = ppb_url_request_interface_->Create( |
| instance_->pp_instance()); |
| ASSERT_NE(url_request, kInvalidResource); |
| |
| TestCompletionCallback callback(instance_->pp_instance(), callback_type()); |
| |
| pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); |
| callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); |
| CHECK_CALLBACK_BEHAVIOR(callback); |
| ASSERT_EQ(PP_OK, callback.result()); |
| |
| pp::FileRef ref(file_system, "/test_file"); |
| pp::FileIO io(instance_); |
| callback.WaitForResult(io.Open(ref, |
| PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE, |
| callback.GetCallback())); |
| CHECK_CALLBACK_BEHAVIOR(callback); |
| ASSERT_EQ(PP_OK, callback.result()); |
| |
| std::string append_data = "hello\n"; |
| callback.WaitForResult(io.Write(0, |
| append_data.c_str(), |
| static_cast<int32_t>(append_data.size()), |
| callback.GetCallback())); |
| CHECK_CALLBACK_BEHAVIOR(callback); |
| ASSERT_EQ(static_cast<int32_t>(append_data.size()), callback.result()); |
| |
| PP_Var post_string_var = PP_MakeString("POST"); |
| PP_Var echo_string_var = PP_MakeString("/echo"); |
| |
| // NULL pointer causes a crash. In general PPAPI implementation does not |
| // test for NULL because they are just a special case of bad pointers that |
| // are not detectable if set to point to an object that does not exist. |
| |
| // Invalid resource should fail. |
| ASSERT_EQ(PP_FALSE, ppb_url_request_interface_->AppendFileToBody( |
| kInvalidResource, ref.pp_resource(), 0, -1, 0)); |
| |
| // Append data and POST to echoing web server. |
| ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty( |
| url_request, PP_URLREQUESTPROPERTY_METHOD, post_string_var)); |
| ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->SetProperty( |
| url_request, PP_URLREQUESTPROPERTY_URL, echo_string_var)); |
| |
| // Append file to body and verify the body is what we expect. |
| ASSERT_EQ(PP_TRUE, ppb_url_request_interface_->AppendFileToBody( |
| url_request, ref.pp_resource(), 0, -1, 0)); |
| std::string error = LoadAndCompareBody(url_request, append_data); |
| |
| ppb_var_interface_->Release(post_string_var); |
| ppb_var_interface_->Release(echo_string_var); |
| ppb_core_interface_->ReleaseResource(url_request); |
| return error; // == PASS() if empty. |
| } |
| |
| // Allocates and manipulates a large number of resources. |
| std::string TestURLRequest::TestStress() { |
| const int kManyResources = 500; |
| PP_Resource url_request_info[kManyResources]; |
| |
| std::string error; |
| int num_created = kManyResources; |
| for (int i = 0; i < kManyResources; i++) { |
| url_request_info[i] = ppb_url_request_interface_->Create( |
| instance_->pp_instance()); |
| if (url_request_info[i] == kInvalidResource) { |
| error = "Create() failed"; |
| } else if (PP_FALSE == ppb_url_request_interface_->IsURLRequestInfo( |
| url_request_info[i])) { |
| error = "IsURLRequestInfo() failed"; |
| } else if (PP_FALSE == ppb_url_request_interface_->SetProperty( |
| url_request_info[i], |
| PP_URLREQUESTPROPERTY_STREAMTOFILE, |
| PP_MakeBool(PP_FALSE))) { |
| error = "SetProperty() failed"; |
| } |
| if (!error.empty()) { |
| num_created = i + 1; |
| break; |
| } |
| } |
| for (int i = 0; i < num_created; i++) { |
| ppb_core_interface_->ReleaseResource(url_request_info[i]); |
| if (PP_TRUE == |
| ppb_url_request_interface_->IsURLRequestInfo(url_request_info[i])) |
| error = "IsURLREquestInfo() succeeded after release"; |
| } |
| return error; // == PASS() if empty. |
| } |