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 #include "ppapi/tests/test_url_loader.h" 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <string> 10 11 #include "ppapi/c/pp_errors.h" 12 #include "ppapi/c/ppb_file_io.h" 13 #include "ppapi/c/ppb_url_loader.h" 14 #include "ppapi/c/trusted/ppb_url_loader_trusted.h" 15 #include "ppapi/cpp/dev/url_util_dev.h" 16 #include "ppapi/cpp/file_io.h" 17 #include "ppapi/cpp/file_ref.h" 18 #include "ppapi/cpp/file_system.h" 19 #include "ppapi/cpp/instance.h" 20 #include "ppapi/cpp/module.h" 21 #include "ppapi/cpp/private/file_io_private.h" 22 #include "ppapi/cpp/url_loader.h" 23 #include "ppapi/cpp/url_request_info.h" 24 #include "ppapi/cpp/url_response_info.h" 25 #include "ppapi/tests/test_utils.h" 26 #include "ppapi/tests/testing_instance.h" 27 28 REGISTER_TEST_CASE(URLLoader); 29 30 namespace { 31 32 int32_t WriteEntireBuffer(PP_Instance instance, 33 pp::FileIO* file_io, 34 int32_t offset, 35 const std::string& data, 36 CallbackType callback_type) { 37 TestCompletionCallback callback(instance, callback_type); 38 int32_t write_offset = offset; 39 const char* buf = data.c_str(); 40 int32_t size = data.size(); 41 42 while (write_offset < offset + size) { 43 callback.WaitForResult(file_io->Write(write_offset, 44 &buf[write_offset - offset], 45 size - write_offset + offset, 46 callback.GetCallback())); 47 if (callback.result() < 0) 48 return callback.result(); 49 if (callback.result() == 0) 50 return PP_ERROR_FAILED; 51 write_offset += callback.result(); 52 } 53 54 return PP_OK; 55 } 56 57 } // namespace 58 59 TestURLLoader::TestURLLoader(TestingInstance* instance) 60 : TestCase(instance), 61 file_io_private_interface_(NULL), 62 url_loader_trusted_interface_(NULL) { 63 } 64 65 bool TestURLLoader::Init() { 66 if (!CheckTestingInterface()) { 67 instance_->AppendError("Testing interface not available"); 68 return false; 69 } 70 71 const PPB_FileIO* file_io_interface = static_cast<const PPB_FileIO*>( 72 pp::Module::Get()->GetBrowserInterface(PPB_FILEIO_INTERFACE)); 73 if (!file_io_interface) 74 instance_->AppendError("FileIO interface not available"); 75 76 file_io_private_interface_ = static_cast<const PPB_FileIO_Private*>( 77 pp::Module::Get()->GetBrowserInterface(PPB_FILEIO_PRIVATE_INTERFACE)); 78 if (!file_io_private_interface_) 79 instance_->AppendError("FileIO_Private interface not available"); 80 url_loader_trusted_interface_ = static_cast<const PPB_URLLoaderTrusted*>( 81 pp::Module::Get()->GetBrowserInterface(PPB_URLLOADERTRUSTED_INTERFACE)); 82 if (!testing_interface_->IsOutOfProcess()) { 83 // Trusted interfaces are not supported under NaCl. 84 #if !(defined __native_client__) 85 if (!url_loader_trusted_interface_) 86 instance_->AppendError("URLLoaderTrusted interface not available"); 87 #else 88 if (url_loader_trusted_interface_) 89 instance_->AppendError("URLLoaderTrusted interface is supported by NaCl"); 90 #endif 91 } 92 return EnsureRunningOverHTTP(); 93 } 94 95 /* 96 * The test order is important here, as running tests out of order may cause 97 * test timeout. 98 * 99 * Here is the environment: 100 * 101 * 1. TestServer.py only accepts one open connection at the time. 102 * 2. HTTP socket pool keeps sockets open for several seconds after last use 103 * (hoping that there will be another request that could reuse the connection). 104 * 3. HTTP socket pool is separated by host/port and privacy mode (which is 105 * based on cookies set/get permissions). So, connections to 127.0.0.1, 106 * localhost and localhost in privacy mode cannot reuse existing socket and will 107 * try to open another connection. 108 * 109 * Here is the problem: 110 * 111 * Original test order was repeatedly accessing 127.0.0.1, localhost and 112 * localhost in privacy mode, causing new sockets to open and try to connect to 113 * testserver, which they couldn't until previous connection is closed by socket 114 * pool idle socket timeout (10 seconds). 115 * 116 * Because of this the test run was taking around 45 seconds, and test was 117 * reported as 'timed out' by trybot. 118 * 119 * Re-ordering of tests provides more sequential access to 127.0.0.1, localhost 120 * and localhost in privacy mode. It decreases the number of times when socket 121 * pool doesn't have existing connection to host and has to wait, therefore 122 * reducing total test time and ensuring its completion under 30 seconds. 123 */ 124 void TestURLLoader::RunTests(const std::string& filter) { 125 // These tests connect to 127.0.0.1: 126 RUN_CALLBACK_TEST(TestURLLoader, BasicGET, filter); 127 RUN_CALLBACK_TEST(TestURLLoader, BasicPOST, filter); 128 RUN_CALLBACK_TEST(TestURLLoader, BasicFilePOST, filter); 129 RUN_CALLBACK_TEST(TestURLLoader, BasicFileRangePOST, filter); 130 RUN_CALLBACK_TEST(TestURLLoader, CompoundBodyPOST, filter); 131 RUN_CALLBACK_TEST(TestURLLoader, EmptyDataPOST, filter); 132 RUN_CALLBACK_TEST(TestURLLoader, BinaryDataPOST, filter); 133 RUN_CALLBACK_TEST(TestURLLoader, CustomRequestHeader, filter); 134 RUN_CALLBACK_TEST(TestURLLoader, FailsBogusContentLength, filter); 135 RUN_CALLBACK_TEST(TestURLLoader, StreamToFile, filter); 136 RUN_CALLBACK_TEST(TestURLLoader, UntrustedJavascriptURLRestriction, filter); 137 RUN_CALLBACK_TEST(TestURLLoader, TrustedJavascriptURLRestriction, filter); 138 RUN_CALLBACK_TEST(TestURLLoader, UntrustedHttpRequests, filter); 139 RUN_CALLBACK_TEST(TestURLLoader, TrustedHttpRequests, filter); 140 RUN_CALLBACK_TEST(TestURLLoader, FollowURLRedirect, filter); 141 RUN_CALLBACK_TEST(TestURLLoader, AuditURLRedirect, filter); 142 RUN_CALLBACK_TEST(TestURLLoader, AbortCalls, filter); 143 RUN_CALLBACK_TEST(TestURLLoader, UntendedLoad, filter); 144 RUN_CALLBACK_TEST(TestURLLoader, PrefetchBufferThreshold, filter); 145 RUN_CALLBACK_TEST(TestURLLoader, XRequestedWithHeader, filter); 146 // These tests connect to localhost with privacy mode enabled: 147 RUN_CALLBACK_TEST(TestURLLoader, UntrustedSameOriginRestriction, filter); 148 RUN_CALLBACK_TEST(TestURLLoader, UntrustedCrossOriginRequest, filter); 149 // These tests connect to localhost with privacy mode disabled: 150 RUN_CALLBACK_TEST(TestURLLoader, TrustedSameOriginRestriction, filter); 151 RUN_CALLBACK_TEST(TestURLLoader, TrustedCrossOriginRequest, filter); 152 } 153 154 std::string TestURLLoader::ReadEntireFile(pp::FileIO* file_io, 155 std::string* data) { 156 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 157 char buf[256]; 158 int64_t offset = 0; 159 160 for (;;) { 161 callback.WaitForResult(file_io->Read(offset, buf, sizeof(buf), 162 callback.GetCallback())); 163 if (callback.result() < 0) 164 return ReportError("FileIO::Read", callback.result()); 165 if (callback.result() == 0) 166 break; 167 offset += callback.result(); 168 data->append(buf, callback.result()); 169 } 170 171 PASS(); 172 } 173 174 std::string TestURLLoader::ReadEntireResponseBody(pp::URLLoader* loader, 175 std::string* body) { 176 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 177 char buf[2]; // Small so that multiple reads are needed. 178 179 for (;;) { 180 callback.WaitForResult( 181 loader->ReadResponseBody(buf, sizeof(buf), callback.GetCallback())); 182 if (callback.result() < 0) 183 return ReportError("URLLoader::ReadResponseBody", callback.result()); 184 if (callback.result() == 0) 185 break; 186 body->append(buf, callback.result()); 187 } 188 189 PASS(); 190 } 191 192 std::string TestURLLoader::LoadAndCompareBody( 193 const pp::URLRequestInfo& request, 194 const std::string& expected_body) { 195 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 196 197 pp::URLLoader loader(instance_); 198 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 199 CHECK_CALLBACK_BEHAVIOR(callback); 200 ASSERT_EQ(PP_OK, callback.result()); 201 202 pp::URLResponseInfo response_info(loader.GetResponseInfo()); 203 if (response_info.is_null()) 204 return "URLLoader::GetResponseInfo returned null"; 205 int32_t status_code = response_info.GetStatusCode(); 206 if (status_code != 200) 207 return "Unexpected HTTP status code"; 208 209 std::string body; 210 std::string error = ReadEntireResponseBody(&loader, &body); 211 if (!error.empty()) 212 return error; 213 214 if (body.size() != expected_body.size()) 215 return "URLLoader::ReadResponseBody returned unexpected content length"; 216 if (body != expected_body) 217 return "URLLoader::ReadResponseBody returned unexpected content"; 218 219 PASS(); 220 } 221 222 int32_t TestURLLoader::OpenFileSystem(pp::FileSystem* file_system, 223 std::string* message) { 224 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 225 callback.WaitForResult(file_system->Open(1024, callback.GetCallback())); 226 if (callback.failed()) { 227 message->assign(callback.errors()); 228 return callback.result(); 229 } 230 if (callback.result() != PP_OK) { 231 message->assign("FileSystem::Open"); 232 return callback.result(); 233 } 234 return callback.result(); 235 } 236 237 int32_t TestURLLoader::PrepareFileForPost( 238 const pp::FileRef& file_ref, 239 const std::string& data, 240 std::string* message) { 241 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 242 pp::FileIO file_io(instance_); 243 callback.WaitForResult(file_io.Open(file_ref, 244 PP_FILEOPENFLAG_CREATE | 245 PP_FILEOPENFLAG_TRUNCATE | 246 PP_FILEOPENFLAG_WRITE, 247 callback.GetCallback())); 248 if (callback.failed()) { 249 message->assign(callback.errors()); 250 return callback.result(); 251 } 252 if (callback.result() != PP_OK) { 253 message->assign("FileIO::Open failed."); 254 return callback.result(); 255 } 256 257 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, data, 258 callback_type()); 259 if (rv != PP_OK) { 260 message->assign("FileIO::Write failed."); 261 return rv; 262 } 263 264 return rv; 265 } 266 267 std::string TestURLLoader::GetReachableAbsoluteURL( 268 const std::string& file_name) { 269 // Get the absolute page URL and replace the test case file name 270 // with the given one. 271 pp::Var document_url( 272 pp::PASS_REF, 273 testing_interface_->GetDocumentURL(instance_->pp_instance(), 274 NULL)); 275 std::string url(document_url.AsString()); 276 std::string old_name("test_case.html"); 277 size_t index = url.find(old_name); 278 ASSERT_NE(index, std::string::npos); 279 url.replace(index, old_name.length(), file_name); 280 return url; 281 } 282 283 std::string TestURLLoader::GetReachableCrossOriginURL( 284 const std::string& file_name) { 285 // Get an absolute URL and use it to construct a URL that will be 286 // considered cross-origin by the CORS access control code, and yet be 287 // reachable by the test server. 288 std::string url = GetReachableAbsoluteURL(file_name); 289 // Replace '127.0.0.1' with 'localhost'. 290 std::string host("127.0.0.1"); 291 size_t index = url.find(host); 292 ASSERT_NE(index, std::string::npos); 293 url.replace(index, host.length(), "localhost"); 294 return url; 295 } 296 297 int32_t TestURLLoader::OpenUntrusted(const std::string& method, 298 const std::string& header) { 299 pp::URLRequestInfo request(instance_); 300 request.SetURL("/echo"); 301 request.SetMethod(method); 302 request.SetHeaders(header); 303 304 return OpenUntrusted(request); 305 } 306 307 int32_t TestURLLoader::OpenTrusted(const std::string& method, 308 const std::string& header) { 309 pp::URLRequestInfo request(instance_); 310 request.SetURL("/echo"); 311 request.SetMethod(method); 312 request.SetHeaders(header); 313 314 return OpenTrusted(request); 315 } 316 317 int32_t TestURLLoader::OpenUntrusted(const pp::URLRequestInfo& request) { 318 return Open(request, false); 319 } 320 321 int32_t TestURLLoader::OpenTrusted(const pp::URLRequestInfo& request) { 322 return Open(request, true); 323 } 324 325 int32_t TestURLLoader::Open(const pp::URLRequestInfo& request, 326 bool trusted) { 327 pp::URLLoader loader(instance_); 328 if (trusted) 329 url_loader_trusted_interface_->GrantUniversalAccess(loader.pp_resource()); 330 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 331 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 332 return callback.result(); 333 } 334 335 std::string TestURLLoader::TestBasicGET() { 336 pp::URLRequestInfo request(instance_); 337 request.SetURL("test_url_loader_data/hello.txt"); 338 return LoadAndCompareBody(request, "hello\n"); 339 } 340 341 std::string TestURLLoader::TestBasicPOST() { 342 pp::URLRequestInfo request(instance_); 343 request.SetURL("/echo"); 344 request.SetMethod("POST"); 345 std::string postdata("postdata"); 346 request.AppendDataToBody(postdata.data(), postdata.length()); 347 return LoadAndCompareBody(request, postdata); 348 } 349 350 std::string TestURLLoader::TestBasicFilePOST() { 351 std::string message; 352 353 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 354 int32_t rv = OpenFileSystem(&file_system, &message); 355 if (rv != PP_OK) 356 return ReportError(message.c_str(), rv); 357 358 pp::FileRef file_ref(file_system, "/file_post_test"); 359 std::string postdata("postdata"); 360 rv = PrepareFileForPost(file_ref, postdata, &message); 361 if (rv != PP_OK) 362 return ReportError(message.c_str(), rv); 363 364 pp::URLRequestInfo request(instance_); 365 request.SetURL("/echo"); 366 request.SetMethod("POST"); 367 request.AppendFileToBody(file_ref, 0); 368 return LoadAndCompareBody(request, postdata); 369 } 370 371 std::string TestURLLoader::TestBasicFileRangePOST() { 372 std::string message; 373 374 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 375 int32_t rv = OpenFileSystem(&file_system, &message); 376 if (rv != PP_OK) 377 return ReportError(message.c_str(), rv); 378 379 pp::FileRef file_ref(file_system, "/file_range_post_test"); 380 std::string postdata("postdatapostdata"); 381 rv = PrepareFileForPost(file_ref, postdata, &message); 382 if (rv != PP_OK) 383 return ReportError(message.c_str(), rv); 384 385 pp::URLRequestInfo request(instance_); 386 request.SetURL("/echo"); 387 request.SetMethod("POST"); 388 request.AppendFileRangeToBody(file_ref, 4, 12, 0); 389 return LoadAndCompareBody(request, postdata.substr(4, 12)); 390 } 391 392 std::string TestURLLoader::TestCompoundBodyPOST() { 393 pp::URLRequestInfo request(instance_); 394 request.SetURL("/echo"); 395 request.SetMethod("POST"); 396 std::string postdata1("post"); 397 request.AppendDataToBody(postdata1.data(), postdata1.length()); 398 std::string postdata2("data"); 399 request.AppendDataToBody(postdata2.data(), postdata2.length()); 400 return LoadAndCompareBody(request, postdata1 + postdata2); 401 } 402 403 std::string TestURLLoader::TestEmptyDataPOST() { 404 pp::URLRequestInfo request(instance_); 405 request.SetURL("/echo"); 406 request.SetMethod("POST"); 407 request.AppendDataToBody("", 0); 408 return LoadAndCompareBody(request, std::string()); 409 } 410 411 std::string TestURLLoader::TestBinaryDataPOST() { 412 pp::URLRequestInfo request(instance_); 413 request.SetURL("/echo"); 414 request.SetMethod("POST"); 415 const char postdata_chars[] = 416 "\x00\x01\x02\x03\x04\x05postdata\xfa\xfb\xfc\xfd\xfe\xff"; 417 std::string postdata(postdata_chars, 418 sizeof(postdata_chars) / sizeof(postdata_chars[0])); 419 request.AppendDataToBody(postdata.data(), postdata.length()); 420 return LoadAndCompareBody(request, postdata); 421 } 422 423 std::string TestURLLoader::TestCustomRequestHeader() { 424 pp::URLRequestInfo request(instance_); 425 request.SetURL("/echoheader?Foo"); 426 request.SetHeaders("Foo: 1"); 427 return LoadAndCompareBody(request, "1"); 428 } 429 430 std::string TestURLLoader::TestFailsBogusContentLength() { 431 pp::URLRequestInfo request(instance_); 432 request.SetURL("/echo"); 433 request.SetMethod("POST"); 434 request.SetHeaders("Content-Length: 400"); 435 std::string postdata("postdata"); 436 request.AppendDataToBody(postdata.data(), postdata.length()); 437 438 int32_t rv; 439 rv = OpenUntrusted(request); 440 if (rv != PP_ERROR_NOACCESS) 441 return ReportError( 442 "Untrusted request with bogus Content-Length restriction", rv); 443 444 PASS(); 445 } 446 447 std::string TestURLLoader::TestStreamToFile() { 448 pp::URLRequestInfo request(instance_); 449 request.SetURL("test_url_loader_data/hello.txt"); 450 request.SetStreamToFile(true); 451 452 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 453 454 pp::URLLoader loader(instance_); 455 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 456 CHECK_CALLBACK_BEHAVIOR(callback); 457 ASSERT_EQ(PP_OK, callback.result()); 458 459 pp::URLResponseInfo response_info(loader.GetResponseInfo()); 460 if (response_info.is_null()) 461 return "URLLoader::GetResponseInfo returned null"; 462 int32_t status_code = response_info.GetStatusCode(); 463 if (status_code != 200) 464 return "Unexpected HTTP status code"; 465 466 pp::FileRef body(response_info.GetBodyAsFileRef()); 467 if (body.is_null()) 468 return "URLResponseInfo::GetBody returned null"; 469 470 callback.WaitForResult(loader.FinishStreamingToFile(callback.GetCallback())); 471 CHECK_CALLBACK_BEHAVIOR(callback); 472 ASSERT_EQ(PP_OK, callback.result()); 473 474 pp::FileIO reader(instance_); 475 callback.WaitForResult(reader.Open(body, PP_FILEOPENFLAG_READ, 476 callback.GetCallback())); 477 CHECK_CALLBACK_BEHAVIOR(callback); 478 ASSERT_EQ(PP_OK, callback.result()); 479 480 std::string data; 481 std::string error = ReadEntireFile(&reader, &data); 482 if (!error.empty()) 483 return error; 484 485 std::string expected_body = "hello\n"; 486 if (data.size() != expected_body.size()) 487 return "ReadEntireFile returned unexpected content length"; 488 if (data != expected_body) 489 return "ReadEntireFile returned unexpected content"; 490 491 PASS(); 492 } 493 494 // Untrusted, unintended cross-origin requests should fail. 495 std::string TestURLLoader::TestUntrustedSameOriginRestriction() { 496 pp::URLRequestInfo request(instance_); 497 std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html"); 498 request.SetURL(cross_origin_url); 499 500 int32_t rv = OpenUntrusted(request); 501 if (rv != PP_ERROR_NOACCESS) 502 return ReportError( 503 "Untrusted, unintended cross-origin request restriction", rv); 504 505 PASS(); 506 } 507 508 // Trusted, unintended cross-origin requests should succeed. 509 std::string TestURLLoader::TestTrustedSameOriginRestriction() { 510 pp::URLRequestInfo request(instance_); 511 std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html"); 512 request.SetURL(cross_origin_url); 513 514 int32_t rv = OpenTrusted(request); 515 if (rv != PP_OK) 516 return ReportError("Trusted cross-origin request failed", rv); 517 518 PASS(); 519 } 520 521 // Untrusted, intended cross-origin requests should use CORS and succeed. 522 std::string TestURLLoader::TestUntrustedCrossOriginRequest() { 523 pp::URLRequestInfo request(instance_); 524 std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html"); 525 request.SetURL(cross_origin_url); 526 request.SetAllowCrossOriginRequests(true); 527 528 int32_t rv = OpenUntrusted(request); 529 if (rv != PP_OK) 530 return ReportError( 531 "Untrusted, intended cross-origin request failed", rv); 532 533 PASS(); 534 } 535 536 // Trusted, intended cross-origin requests should use CORS and succeed. 537 std::string TestURLLoader::TestTrustedCrossOriginRequest() { 538 pp::URLRequestInfo request(instance_); 539 std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html"); 540 request.SetURL(cross_origin_url); 541 request.SetAllowCrossOriginRequests(true); 542 543 int32_t rv = OpenTrusted(request); 544 if (rv != PP_OK) 545 return ReportError("Trusted cross-origin request failed", rv); 546 547 PASS(); 548 } 549 550 // Untrusted Javascript URLs requests should fail. 551 std::string TestURLLoader::TestUntrustedJavascriptURLRestriction() { 552 pp::URLRequestInfo request(instance_); 553 request.SetURL("javascript:foo = bar"); 554 555 int32_t rv = OpenUntrusted(request); 556 if (rv != PP_ERROR_NOACCESS) 557 return ReportError( 558 "Untrusted Javascript URL request restriction failed", rv); 559 560 PASS(); 561 } 562 563 // Trusted Javascript URLs requests should succeed. 564 std::string TestURLLoader::TestTrustedJavascriptURLRestriction() { 565 pp::URLRequestInfo request(instance_); 566 request.SetURL("javascript:foo = bar"); 567 568 int32_t rv = OpenTrusted(request); 569 if (rv == PP_ERROR_NOACCESS) 570 return ReportError( 571 "Trusted Javascript URL request", rv); 572 573 PASS(); 574 } 575 576 std::string TestURLLoader::TestUntrustedHttpRequests() { 577 // HTTP methods are restricted only for untrusted loaders. Forbidden 578 // methods are CONNECT, TRACE, and TRACK, and any string that is not a 579 // valid token (containing special characters like CR, LF). 580 // http://www.w3.org/TR/XMLHttpRequest/ 581 { 582 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("cOnNeCt", std::string())); 583 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("tRaCk", std::string())); 584 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("tRaCe", std::string())); 585 ASSERT_EQ(PP_ERROR_NOACCESS, 586 OpenUntrusted("POST\x0d\x0ax-csrf-token:\x20test1234", std::string())); 587 } 588 // HTTP methods are restricted only for untrusted loaders. Try all headers 589 // that are forbidden by http://www.w3.org/TR/XMLHttpRequest/. 590 { 591 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Accept-Charset:\n")); 592 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Accept-Encoding:\n")); 593 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Connection:\n")); 594 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Content-Length:\n")); 595 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Cookie:\n")); 596 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Cookie2:\n")); 597 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Date:\n")); 598 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Dnt:\n")); 599 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Expect:\n")); 600 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Host:\n")); 601 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Keep-Alive:\n")); 602 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Referer:\n")); 603 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "TE:\n")); 604 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Trailer:\n")); 605 ASSERT_EQ(PP_ERROR_NOACCESS, 606 OpenUntrusted("GET", "Transfer-Encoding:\n")); 607 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Upgrade:\n")); 608 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "User-Agent:\n")); 609 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Via:\n")); 610 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted( 611 "GET", "Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA==:\n")); 612 ASSERT_EQ(PP_ERROR_NOACCESS, OpenUntrusted("GET", "Sec-foo:\n")); 613 } 614 // Untrusted requests with custom referrer should fail. 615 { 616 pp::URLRequestInfo request(instance_); 617 request.SetCustomReferrerURL("http://www.google.com/"); 618 619 int32_t rv = OpenUntrusted(request); 620 if (rv != PP_ERROR_NOACCESS) 621 return ReportError( 622 "Untrusted request with custom referrer restriction", rv); 623 } 624 // Untrusted requests with custom transfer encodings should fail. 625 { 626 pp::URLRequestInfo request(instance_); 627 request.SetCustomContentTransferEncoding("foo"); 628 629 int32_t rv = OpenUntrusted(request); 630 if (rv != PP_ERROR_NOACCESS) 631 return ReportError( 632 "Untrusted request with content-transfer-encoding restriction", rv); 633 } 634 635 PASS(); 636 } 637 638 std::string TestURLLoader::TestTrustedHttpRequests() { 639 // Trusted requests can use restricted methods. 640 { 641 ASSERT_EQ(PP_OK, OpenTrusted("cOnNeCt", std::string())); 642 ASSERT_EQ(PP_OK, OpenTrusted("tRaCk", std::string())); 643 ASSERT_EQ(PP_OK, OpenTrusted("tRaCe", std::string())); 644 } 645 // Trusted requests can use restricted headers. 646 { 647 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Accept-Charset:\n")); 648 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Accept-Encoding:\n")); 649 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Connection:\n")); 650 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Content-Length:\n")); 651 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Cookie:\n")); 652 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Cookie2:\n")); 653 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Content-Transfer-Encoding:\n")); 654 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Date:\n")); 655 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Expect:\n")); 656 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Host:\n")); 657 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Keep-Alive:\n")); 658 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Referer:\n")); 659 ASSERT_EQ(PP_OK, OpenTrusted("GET", "TE:\n")); 660 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Trailer:\n")); 661 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Transfer-Encoding:\n")); 662 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Upgrade:\n")); 663 ASSERT_EQ(PP_OK, OpenTrusted("GET", "User-Agent:\n")); 664 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Via:\n")); 665 ASSERT_EQ(PP_OK, 666 OpenTrusted("GET", 667 "Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA==:\n")); 668 ASSERT_EQ(PP_OK, OpenTrusted("GET", "Sec-foo:\n")); 669 } 670 // Trusted requests with custom referrer should succeed. 671 { 672 pp::URLRequestInfo request(instance_); 673 request.SetCustomReferrerURL("http://www.google.com/"); 674 675 int32_t rv = OpenTrusted(request); 676 if (rv != PP_OK) 677 return ReportError("Trusted request with custom referrer", rv); 678 } 679 // Trusted requests with custom transfer encodings should succeed. 680 { 681 pp::URLRequestInfo request(instance_); 682 request.SetCustomContentTransferEncoding("foo"); 683 684 int32_t rv = OpenTrusted(request); 685 if (rv != PP_OK) 686 return ReportError( 687 "Trusted request with content-transfer-encoding failed", rv); 688 } 689 690 PASS(); 691 } 692 693 // This test should cause a redirect and ensure that the loader follows it. 694 std::string TestURLLoader::TestFollowURLRedirect() { 695 pp::URLRequestInfo request(instance_); 696 // This prefix causes the test server to return a 301 redirect. 697 std::string redirect_prefix("/server-redirect?"); 698 // We need an absolute path for the redirect to actually work. 699 std::string redirect_url = 700 GetReachableAbsoluteURL("test_url_loader_data/hello.txt"); 701 request.SetURL(redirect_prefix.append(redirect_url)); 702 return LoadAndCompareBody(request, "hello\n"); 703 } 704 705 // This test should cause a redirect and ensure that the loader runs 706 // the callback, rather than following the redirect. 707 std::string TestURLLoader::TestAuditURLRedirect() { 708 pp::URLRequestInfo request(instance_); 709 // This path will cause the server to return a 301 redirect. 710 // This prefix causes the test server to return a 301 redirect. 711 std::string redirect_prefix("/server-redirect?"); 712 // We need an absolute path for the redirect to actually work. 713 std::string redirect_url = 714 GetReachableAbsoluteURL("test_url_loader_data/hello.txt"); 715 request.SetURL(redirect_prefix.append(redirect_url)); 716 request.SetFollowRedirects(false); 717 718 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 719 720 pp::URLLoader loader(instance_); 721 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 722 CHECK_CALLBACK_BEHAVIOR(callback); 723 ASSERT_EQ(PP_OK, callback.result()); 724 725 // Checks that the response indicates a redirect, and that the URL 726 // is correct. 727 pp::URLResponseInfo response_info(loader.GetResponseInfo()); 728 if (response_info.is_null()) 729 return "URLLoader::GetResponseInfo returned null"; 730 int32_t status_code = response_info.GetStatusCode(); 731 if (status_code != 301) 732 return "Response status should be 301"; 733 734 // Test that the paused loader can be resumed. 735 callback.WaitForResult(loader.FollowRedirect(callback.GetCallback())); 736 CHECK_CALLBACK_BEHAVIOR(callback); 737 ASSERT_EQ(PP_OK, callback.result()); 738 std::string body; 739 std::string error = ReadEntireResponseBody(&loader, &body); 740 if (!error.empty()) 741 return error; 742 743 if (body != "hello\n") 744 return "URLLoader::FollowRedirect failed"; 745 746 PASS(); 747 } 748 749 std::string TestURLLoader::TestAbortCalls() { 750 pp::URLRequestInfo request(instance_); 751 request.SetURL("test_url_loader_data/hello.txt"); 752 753 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 754 int32_t rv; 755 756 // Abort |Open()|. 757 { 758 rv = pp::URLLoader(instance_).Open(request, callback.GetCallback()); 759 } 760 callback.WaitForAbortResult(rv); 761 CHECK_CALLBACK_BEHAVIOR(callback); 762 763 // Abort |ReadResponseBody()|. 764 { 765 char buf[2] = { 0 }; 766 { 767 pp::URLLoader loader(instance_); 768 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 769 CHECK_CALLBACK_BEHAVIOR(callback); 770 ASSERT_EQ(PP_OK, callback.result()); 771 772 rv = loader.ReadResponseBody(buf, sizeof(buf), callback.GetCallback()); 773 } // Destroy |loader|. 774 callback.WaitForAbortResult(rv); 775 CHECK_CALLBACK_BEHAVIOR(callback); 776 if (rv == PP_OK_COMPLETIONPENDING) { 777 if (buf[0] || buf[1]) { 778 return "URLLoader::ReadResponseBody wrote data after resource " 779 "destruction."; 780 } 781 } 782 } 783 784 // TODO(viettrungluu): More abort tests (but add basic tests first). 785 // Also test that Close() aborts properly. crbug.com/69457 786 787 PASS(); 788 } 789 790 std::string TestURLLoader::TestUntendedLoad() { 791 pp::URLRequestInfo request(instance_); 792 request.SetURL("test_url_loader_data/hello.txt"); 793 request.SetRecordDownloadProgress(true); 794 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 795 796 pp::URLLoader loader(instance_); 797 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 798 CHECK_CALLBACK_BEHAVIOR(callback); 799 ASSERT_EQ(PP_OK, callback.result()); 800 801 // We received the response callback. Yield until the network code has called 802 // the loader's didReceiveData and didFinishLoading methods before we give it 803 // another callback function, to make sure the loader works with no callback. 804 int64_t bytes_received = 0; 805 int64_t total_bytes_to_be_received = 0; 806 while (true) { 807 loader.GetDownloadProgress(&bytes_received, &total_bytes_to_be_received); 808 if (total_bytes_to_be_received <= 0) 809 return ReportError("URLLoader::GetDownloadProgress total size", 810 total_bytes_to_be_received); 811 if (bytes_received == total_bytes_to_be_received) 812 break; 813 // Yield if we're on the main thread, so that URLLoader can receive more 814 // data. 815 if (pp::Module::Get()->core()->IsMainThread()) { 816 NestedEvent event(instance_->pp_instance()); 817 event.PostSignal(10); 818 event.Wait(); 819 } 820 } 821 // The loader should now have the data and have finished successfully. 822 std::string body; 823 std::string error = ReadEntireResponseBody(&loader, &body); 824 if (!error.empty()) 825 return error; 826 if (body != "hello\n") 827 return ReportError("Couldn't read data", callback.result()); 828 829 PASS(); 830 } 831 832 int32_t TestURLLoader::OpenWithPrefetchBufferThreshold(int32_t lower, 833 int32_t upper) { 834 pp::URLRequestInfo request(instance_); 835 request.SetURL("test_url_loader_data/hello.txt"); 836 request.SetPrefetchBufferLowerThreshold(lower); 837 request.SetPrefetchBufferUpperThreshold(upper); 838 839 return OpenUntrusted(request); 840 } 841 842 std::string TestURLLoader::TestPrefetchBufferThreshold() { 843 int32_t rv = OpenWithPrefetchBufferThreshold(-1, 1); 844 if (rv != PP_ERROR_FAILED) { 845 return ReportError("The prefetch limits contained a negative value but " 846 "the URLLoader did not fail.", rv); 847 } 848 849 rv = OpenWithPrefetchBufferThreshold(0, 1); 850 if (rv != PP_OK) { 851 return ReportError("The prefetch buffer limits were legal values but " 852 "the URLLoader failed.", rv); 853 } 854 855 rv = OpenWithPrefetchBufferThreshold(1000, 1); 856 if (rv != PP_ERROR_FAILED) { 857 return ReportError("The lower buffer value was higher than the upper but " 858 "the URLLoader did not fail.", rv); 859 } 860 861 PASS(); 862 } 863 864 // TODO(viettrungluu): This test properly belongs elsewhere. It tests that 865 // Chrome properly tags URL requests made on behalf of Pepper plugins (with an 866 // X-Requested-With header), but this isn't, strictly speaking, a PPAPI 867 // behavior. 868 std::string TestURLLoader::TestXRequestedWithHeader() { 869 pp::URLRequestInfo request(instance_); 870 request.SetURL("/echoheader?X-Requested-With"); 871 // The name and version of the plugin is set from the command-line (see 872 // chrome/test/ppapi/ppapi_test.cc. 873 return LoadAndCompareBody(request, "PPAPITests/1.2.3"); 874 } 875 876 // TODO(viettrungluu): Add tests for Get{Upload,Download}Progress, Close 877 // (including abort tests if applicable). 878