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