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 // These tests connect to localhost with privacy mode enabled: 146 RUN_CALLBACK_TEST(TestURLLoader, UntrustedSameOriginRestriction, filter); 147 RUN_CALLBACK_TEST(TestURLLoader, UntrustedCrossOriginRequest, filter); 148 // These tests connect to localhost with privacy mode disabled: 149 RUN_CALLBACK_TEST(TestURLLoader, TrustedSameOriginRestriction, filter); 150 RUN_CALLBACK_TEST(TestURLLoader, TrustedCrossOriginRequest, filter); 151 } 152 153 std::string TestURLLoader::ReadEntireFile(pp::FileIO* file_io, 154 std::string* data) { 155 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 156 char buf[256]; 157 int64_t offset = 0; 158 159 for (;;) { 160 callback.WaitForResult(file_io->Read(offset, buf, sizeof(buf), 161 callback.GetCallback())); 162 if (callback.result() < 0) 163 return ReportError("FileIO::Read", callback.result()); 164 if (callback.result() == 0) 165 break; 166 offset += callback.result(); 167 data->append(buf, callback.result()); 168 } 169 170 PASS(); 171 } 172 173 std::string TestURLLoader::ReadEntireResponseBody(pp::URLLoader* loader, 174 std::string* body) { 175 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 176 char buf[2]; // Small so that multiple reads are needed. 177 178 for (;;) { 179 callback.WaitForResult( 180 loader->ReadResponseBody(buf, sizeof(buf), callback.GetCallback())); 181 if (callback.result() < 0) 182 return ReportError("URLLoader::ReadResponseBody", callback.result()); 183 if (callback.result() == 0) 184 break; 185 body->append(buf, callback.result()); 186 } 187 188 PASS(); 189 } 190 191 std::string TestURLLoader::LoadAndCompareBody( 192 const pp::URLRequestInfo& request, 193 const std::string& expected_body) { 194 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 195 196 pp::URLLoader loader(instance_); 197 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 198 CHECK_CALLBACK_BEHAVIOR(callback); 199 ASSERT_EQ(PP_OK, callback.result()); 200 201 pp::URLResponseInfo response_info(loader.GetResponseInfo()); 202 if (response_info.is_null()) 203 return "URLLoader::GetResponseInfo returned null"; 204 int32_t status_code = response_info.GetStatusCode(); 205 if (status_code != 200) 206 return "Unexpected HTTP status code"; 207 208 std::string body; 209 std::string error = ReadEntireResponseBody(&loader, &body); 210 if (!error.empty()) 211 return error; 212 213 if (body.size() != expected_body.size()) 214 return "URLLoader::ReadResponseBody returned unexpected content length"; 215 if (body != expected_body) 216 return "URLLoader::ReadResponseBody returned unexpected content"; 217 218 PASS(); 219 } 220 221 int32_t TestURLLoader::OpenFileSystem(pp::FileSystem* file_system, 222 std::string* message) { 223 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 224 callback.WaitForResult(file_system->Open(1024, callback.GetCallback())); 225 if (callback.failed()) { 226 message->assign(callback.errors()); 227 return callback.result(); 228 } 229 if (callback.result() != PP_OK) { 230 message->assign("FileSystem::Open"); 231 return callback.result(); 232 } 233 return callback.result(); 234 } 235 236 int32_t TestURLLoader::PrepareFileForPost( 237 const pp::FileRef& file_ref, 238 const std::string& data, 239 std::string* message) { 240 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 241 pp::FileIO file_io(instance_); 242 callback.WaitForResult(file_io.Open(file_ref, 243 PP_FILEOPENFLAG_CREATE | 244 PP_FILEOPENFLAG_TRUNCATE | 245 PP_FILEOPENFLAG_WRITE, 246 callback.GetCallback())); 247 if (callback.failed()) { 248 message->assign(callback.errors()); 249 return callback.result(); 250 } 251 if (callback.result() != PP_OK) { 252 message->assign("FileIO::Open failed."); 253 return callback.result(); 254 } 255 256 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, data, 257 callback_type()); 258 if (rv != PP_OK) { 259 message->assign("FileIO::Write failed."); 260 return rv; 261 } 262 263 return rv; 264 } 265 266 std::string TestURLLoader::GetReachableAbsoluteURL( 267 const std::string& file_name) { 268 // Get the absolute page URL and replace the test case file name 269 // with the given one. 270 pp::Var document_url( 271 pp::PASS_REF, 272 testing_interface_->GetDocumentURL(instance_->pp_instance(), 273 NULL)); 274 std::string url(document_url.AsString()); 275 std::string old_name("test_case.html"); 276 size_t index = url.find(old_name); 277 ASSERT_NE(index, std::string::npos); 278 url.replace(index, old_name.length(), file_name); 279 return url; 280 } 281 282 std::string TestURLLoader::GetReachableCrossOriginURL( 283 const std::string& file_name) { 284 // Get an absolute URL and use it to construct a URL that will be 285 // considered cross-origin by the CORS access control code, and yet be 286 // reachable by the test server. 287 std::string url = GetReachableAbsoluteURL(file_name); 288 // Replace '127.0.0.1' with 'localhost'. 289 std::string host("127.0.0.1"); 290 size_t index = url.find(host); 291 ASSERT_NE(index, std::string::npos); 292 url.replace(index, host.length(), "localhost"); 293 return url; 294 } 295 296 int32_t TestURLLoader::OpenUntrusted(const std::string& method, 297 const std::string& header) { 298 pp::URLRequestInfo request(instance_); 299 request.SetURL("/echo"); 300 request.SetMethod(method); 301 request.SetHeaders(header); 302 303 return OpenUntrusted(request); 304 } 305 306 int32_t TestURLLoader::OpenTrusted(const std::string& method, 307 const std::string& header) { 308 pp::URLRequestInfo request(instance_); 309 request.SetURL("/echo"); 310 request.SetMethod(method); 311 request.SetHeaders(header); 312 313 return OpenTrusted(request); 314 } 315 316 int32_t TestURLLoader::OpenUntrusted(const pp::URLRequestInfo& request) { 317 return Open(request, false); 318 } 319 320 int32_t TestURLLoader::OpenTrusted(const pp::URLRequestInfo& request) { 321 return Open(request, true); 322 } 323 324 int32_t TestURLLoader::Open(const pp::URLRequestInfo& request, 325 bool trusted) { 326 pp::URLLoader loader(instance_); 327 if (trusted) 328 url_loader_trusted_interface_->GrantUniversalAccess(loader.pp_resource()); 329 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 330 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 331 return callback.result(); 332 } 333 334 std::string TestURLLoader::TestBasicGET() { 335 pp::URLRequestInfo request(instance_); 336 request.SetURL("test_url_loader_data/hello.txt"); 337 return LoadAndCompareBody(request, "hello\n"); 338 } 339 340 std::string TestURLLoader::TestBasicPOST() { 341 pp::URLRequestInfo request(instance_); 342 request.SetURL("/echo"); 343 request.SetMethod("POST"); 344 std::string postdata("postdata"); 345 request.AppendDataToBody(postdata.data(), postdata.length()); 346 return LoadAndCompareBody(request, postdata); 347 } 348 349 std::string TestURLLoader::TestBasicFilePOST() { 350 std::string message; 351 352 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 353 int32_t rv = OpenFileSystem(&file_system, &message); 354 if (rv != PP_OK) 355 return ReportError(message.c_str(), rv); 356 357 pp::FileRef file_ref(file_system, "/file_post_test"); 358 std::string postdata("postdata"); 359 rv = PrepareFileForPost(file_ref, postdata, &message); 360 if (rv != PP_OK) 361 return ReportError(message.c_str(), rv); 362 363 pp::URLRequestInfo request(instance_); 364 request.SetURL("/echo"); 365 request.SetMethod("POST"); 366 request.AppendFileToBody(file_ref, 0); 367 return LoadAndCompareBody(request, postdata); 368 } 369 370 std::string TestURLLoader::TestBasicFileRangePOST() { 371 std::string message; 372 373 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 374 int32_t rv = OpenFileSystem(&file_system, &message); 375 if (rv != PP_OK) 376 return ReportError(message.c_str(), rv); 377 378 pp::FileRef file_ref(file_system, "/file_range_post_test"); 379 std::string postdata("postdatapostdata"); 380 rv = PrepareFileForPost(file_ref, postdata, &message); 381 if (rv != PP_OK) 382 return ReportError(message.c_str(), rv); 383 384 pp::URLRequestInfo request(instance_); 385 request.SetURL("/echo"); 386 request.SetMethod("POST"); 387 request.AppendFileRangeToBody(file_ref, 4, 12, 0); 388 return LoadAndCompareBody(request, postdata.substr(4, 12)); 389 } 390 391 std::string TestURLLoader::TestCompoundBodyPOST() { 392 pp::URLRequestInfo request(instance_); 393 request.SetURL("/echo"); 394 request.SetMethod("POST"); 395 std::string postdata1("post"); 396 request.AppendDataToBody(postdata1.data(), postdata1.length()); 397 std::string postdata2("data"); 398 request.AppendDataToBody(postdata2.data(), postdata2.length()); 399 return LoadAndCompareBody(request, postdata1 + postdata2); 400 } 401 402 std::string TestURLLoader::TestEmptyDataPOST() { 403 pp::URLRequestInfo request(instance_); 404 request.SetURL("/echo"); 405 request.SetMethod("POST"); 406 request.AppendDataToBody("", 0); 407 return LoadAndCompareBody(request, std::string()); 408 } 409 410 std::string TestURLLoader::TestBinaryDataPOST() { 411 pp::URLRequestInfo request(instance_); 412 request.SetURL("/echo"); 413 request.SetMethod("POST"); 414 const char postdata_chars[] = 415 "\x00\x01\x02\x03\x04\x05postdata\xfa\xfb\xfc\xfd\xfe\xff"; 416 std::string postdata(postdata_chars, 417 sizeof(postdata_chars) / sizeof(postdata_chars[0])); 418 request.AppendDataToBody(postdata.data(), postdata.length()); 419 return LoadAndCompareBody(request, postdata); 420 } 421 422 std::string TestURLLoader::TestCustomRequestHeader() { 423 pp::URLRequestInfo request(instance_); 424 request.SetURL("/echoheader?Foo"); 425 request.SetHeaders("Foo: 1"); 426 return LoadAndCompareBody(request, "1"); 427 } 428 429 std::string TestURLLoader::TestFailsBogusContentLength() { 430 pp::URLRequestInfo request(instance_); 431 request.SetURL("/echo"); 432 request.SetMethod("POST"); 433 request.SetHeaders("Content-Length: 400"); 434 std::string postdata("postdata"); 435 request.AppendDataToBody(postdata.data(), postdata.length()); 436 437 int32_t rv; 438 rv = OpenUntrusted(request); 439 if (rv != PP_ERROR_NOACCESS) 440 return ReportError( 441 "Untrusted request with bogus Content-Length restriction", rv); 442 443 PASS(); 444 } 445 446 std::string TestURLLoader::TestStreamToFile() { 447 pp::URLRequestInfo request(instance_); 448 request.SetURL("test_url_loader_data/hello.txt"); 449 request.SetStreamToFile(true); 450 451 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 452 453 pp::URLLoader loader(instance_); 454 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 455 CHECK_CALLBACK_BEHAVIOR(callback); 456 ASSERT_EQ(PP_OK, callback.result()); 457 458 pp::URLResponseInfo response_info(loader.GetResponseInfo()); 459 if (response_info.is_null()) 460 return "URLLoader::GetResponseInfo returned null"; 461 int32_t status_code = response_info.GetStatusCode(); 462 if (status_code != 200) 463 return "Unexpected HTTP status code"; 464 465 pp::FileRef body(response_info.GetBodyAsFileRef()); 466 if (body.is_null()) 467 return "URLResponseInfo::GetBody returned null"; 468 469 callback.WaitForResult(loader.FinishStreamingToFile(callback.GetCallback())); 470 CHECK_CALLBACK_BEHAVIOR(callback); 471 ASSERT_EQ(PP_OK, callback.result()); 472 473 pp::FileIO reader(instance_); 474 callback.WaitForResult(reader.Open(body, PP_FILEOPENFLAG_READ, 475 callback.GetCallback())); 476 CHECK_CALLBACK_BEHAVIOR(callback); 477 ASSERT_EQ(PP_OK, callback.result()); 478 479 std::string data; 480 std::string error = ReadEntireFile(&reader, &data); 481 if (!error.empty()) 482 return error; 483 484 std::string expected_body = "hello\n"; 485 if (data.size() != expected_body.size()) 486 return "ReadEntireFile returned unexpected content length"; 487 if (data != expected_body) 488 return "ReadEntireFile returned unexpected content"; 489 490 PASS(); 491 } 492 493 // Untrusted, unintended cross-origin requests should fail. 494 std::string TestURLLoader::TestUntrustedSameOriginRestriction() { 495 pp::URLRequestInfo request(instance_); 496 std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html"); 497 request.SetURL(cross_origin_url); 498 499 int32_t rv = OpenUntrusted(request); 500 if (rv != PP_ERROR_NOACCESS) 501 return ReportError( 502 "Untrusted, unintended cross-origin request restriction", rv); 503 504 PASS(); 505 } 506 507 // Trusted, unintended cross-origin requests should succeed. 508 std::string TestURLLoader::TestTrustedSameOriginRestriction() { 509 pp::URLRequestInfo request(instance_); 510 std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html"); 511 request.SetURL(cross_origin_url); 512 513 int32_t rv = OpenTrusted(request); 514 if (rv != PP_OK) 515 return ReportError("Trusted cross-origin request failed", rv); 516 517 PASS(); 518 } 519 520 // Untrusted, intended cross-origin requests should use CORS and succeed. 521 std::string TestURLLoader::TestUntrustedCrossOriginRequest() { 522 pp::URLRequestInfo request(instance_); 523 std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html"); 524 request.SetURL(cross_origin_url); 525 request.SetAllowCrossOriginRequests(true); 526 527 int32_t rv = OpenUntrusted(request); 528 if (rv != PP_OK) 529 return ReportError( 530 "Untrusted, intended cross-origin request failed", rv); 531 532 PASS(); 533 } 534 535 // Trusted, intended cross-origin requests should use CORS and succeed. 536 std::string TestURLLoader::TestTrustedCrossOriginRequest() { 537 pp::URLRequestInfo request(instance_); 538 std::string cross_origin_url = GetReachableCrossOriginURL("test_case.html"); 539 request.SetURL(cross_origin_url); 540 request.SetAllowCrossOriginRequests(true); 541 542 int32_t rv = OpenTrusted(request); 543 if (rv != PP_OK) 544 return ReportError("Trusted cross-origin request failed", rv); 545 546 PASS(); 547 } 548 549 // Untrusted Javascript URLs requests should fail. 550 std::string TestURLLoader::TestUntrustedJavascriptURLRestriction() { 551 pp::URLRequestInfo request(instance_); 552 request.SetURL("javascript:foo = bar"); 553 554 int32_t rv = OpenUntrusted(request); 555 if (rv != PP_ERROR_NOACCESS) 556 return ReportError( 557 "Untrusted Javascript URL request restriction failed", rv); 558 559 PASS(); 560 } 561 562 // Trusted Javascript URLs requests should succeed. 563 std::string TestURLLoader::TestTrustedJavascriptURLRestriction() { 564 pp::URLRequestInfo request(instance_); 565 request.SetURL("javascript:foo = bar"); 566 567 int32_t rv = OpenTrusted(request); 568 if (rv == PP_ERROR_NOACCESS) 569 return ReportError( 570 "Trusted Javascript URL request", rv); 571 572 PASS(); 573 } 574 575 std::string TestURLLoader::TestUntrustedHttpRequests() { 576 // HTTP methods are restricted only for untrusted loaders. Forbidden 577 // methods are CONNECT, TRACE, and TRACK, and any string that is not a 578 // valid token (containing special characters like CR, LF). 579 // http://www.w3.org/TR/XMLHttpRequest/ 580 { 581 ASSERT_EQ(OpenUntrusted("cOnNeCt", std::string()), PP_ERROR_NOACCESS); 582 ASSERT_EQ(OpenUntrusted("tRaCk", std::string()), PP_ERROR_NOACCESS); 583 ASSERT_EQ(OpenUntrusted("tRaCe", std::string()), PP_ERROR_NOACCESS); 584 ASSERT_EQ( 585 OpenUntrusted("POST\x0d\x0ax-csrf-token:\x20test1234", std::string()), 586 PP_ERROR_NOACCESS); 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(OpenUntrusted("GET", "Accept-Charset:\n"), PP_ERROR_NOACCESS); 592 ASSERT_EQ(OpenUntrusted("GET", "Accept-Encoding:\n"), PP_ERROR_NOACCESS); 593 ASSERT_EQ(OpenUntrusted("GET", "Connection:\n"), PP_ERROR_NOACCESS); 594 ASSERT_EQ(OpenUntrusted("GET", "Content-Length:\n"), PP_ERROR_NOACCESS); 595 ASSERT_EQ(OpenUntrusted("GET", "Cookie:\n"), PP_ERROR_NOACCESS); 596 ASSERT_EQ(OpenUntrusted("GET", "Cookie2:\n"), PP_ERROR_NOACCESS); 597 ASSERT_EQ(OpenUntrusted( 598 "GET", "Content-Transfer-Encoding:\n"), PP_ERROR_NOACCESS); 599 ASSERT_EQ(OpenUntrusted("GET", "Date:\n"), PP_ERROR_NOACCESS); 600 ASSERT_EQ(OpenUntrusted("GET", "Expect:\n"), PP_ERROR_NOACCESS); 601 ASSERT_EQ(OpenUntrusted("GET", "Host:\n"), PP_ERROR_NOACCESS); 602 ASSERT_EQ(OpenUntrusted("GET", "Keep-Alive:\n"), PP_ERROR_NOACCESS); 603 ASSERT_EQ(OpenUntrusted("GET", "Referer:\n"), PP_ERROR_NOACCESS); 604 ASSERT_EQ(OpenUntrusted("GET", "TE:\n"), PP_ERROR_NOACCESS); 605 ASSERT_EQ(OpenUntrusted("GET", "Trailer:\n"), PP_ERROR_NOACCESS); 606 ASSERT_EQ(OpenUntrusted( 607 "GET", "Transfer-Encoding:\n"), PP_ERROR_NOACCESS); 608 ASSERT_EQ(OpenUntrusted("GET", "Upgrade:\n"), PP_ERROR_NOACCESS); 609 ASSERT_EQ(OpenUntrusted("GET", "User-Agent:\n"), PP_ERROR_NOACCESS); 610 ASSERT_EQ(OpenUntrusted("GET", "Via:\n"), PP_ERROR_NOACCESS); 611 ASSERT_EQ(OpenUntrusted( 612 "GET", "Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA==:\n"), 613 PP_ERROR_NOACCESS); 614 ASSERT_EQ(OpenUntrusted("GET", "Sec-foo:\n"), PP_ERROR_NOACCESS); 615 } 616 // Untrusted requests with custom referrer should fail. 617 { 618 pp::URLRequestInfo request(instance_); 619 request.SetCustomReferrerURL("http://www.google.com/"); 620 621 int32_t rv = OpenUntrusted(request); 622 if (rv != PP_ERROR_NOACCESS) 623 return ReportError( 624 "Untrusted request with custom referrer restriction", rv); 625 } 626 // Untrusted requests with custom transfer encodings should fail. 627 { 628 pp::URLRequestInfo request(instance_); 629 request.SetCustomContentTransferEncoding("foo"); 630 631 int32_t rv = OpenUntrusted(request); 632 if (rv != PP_ERROR_NOACCESS) 633 return ReportError( 634 "Untrusted request with content-transfer-encoding restriction", rv); 635 } 636 637 PASS(); 638 } 639 640 std::string TestURLLoader::TestTrustedHttpRequests() { 641 // Trusted requests can use restricted methods. 642 { 643 ASSERT_EQ(OpenTrusted("cOnNeCt", std::string()), PP_OK); 644 ASSERT_EQ(OpenTrusted("tRaCk", std::string()), PP_OK); 645 ASSERT_EQ(OpenTrusted("tRaCe", std::string()), PP_OK); 646 } 647 // Trusted requests can use restricted headers. 648 { 649 ASSERT_EQ(OpenTrusted("GET", "Accept-Charset:\n"), PP_OK); 650 ASSERT_EQ(OpenTrusted("GET", "Accept-Encoding:\n"), PP_OK); 651 ASSERT_EQ(OpenTrusted("GET", "Connection:\n"), PP_OK); 652 ASSERT_EQ(OpenTrusted("GET", "Content-Length:\n"), PP_OK); 653 ASSERT_EQ(OpenTrusted("GET", "Cookie:\n"), PP_OK); 654 ASSERT_EQ(OpenTrusted("GET", "Cookie2:\n"), PP_OK); 655 ASSERT_EQ(OpenTrusted( 656 "GET", "Content-Transfer-Encoding:\n"), PP_OK); 657 ASSERT_EQ(OpenTrusted("GET", "Date:\n"), PP_OK); 658 ASSERT_EQ(OpenTrusted("GET", "Expect:\n"), PP_OK); 659 ASSERT_EQ(OpenTrusted("GET", "Host:\n"), PP_OK); 660 ASSERT_EQ(OpenTrusted("GET", "Keep-Alive:\n"), PP_OK); 661 ASSERT_EQ(OpenTrusted("GET", "Referer:\n"), PP_OK); 662 ASSERT_EQ(OpenTrusted("GET", "TE:\n"), PP_OK); 663 ASSERT_EQ(OpenTrusted("GET", "Trailer:\n"), PP_OK); 664 ASSERT_EQ(OpenTrusted("GET", "Transfer-Encoding:\n"), PP_OK); 665 ASSERT_EQ(OpenTrusted("GET", "Upgrade:\n"), PP_OK); 666 ASSERT_EQ(OpenTrusted("GET", "User-Agent:\n"), PP_OK); 667 ASSERT_EQ(OpenTrusted("GET", "Via:\n"), PP_OK); 668 ASSERT_EQ(OpenTrusted( 669 "GET", "Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA==:\n"), PP_OK); 670 ASSERT_EQ(OpenTrusted("GET", "Sec-foo:\n"), PP_OK); 671 } 672 // Trusted requests with custom referrer should succeed. 673 { 674 pp::URLRequestInfo request(instance_); 675 request.SetCustomReferrerURL("http://www.google.com/"); 676 677 int32_t rv = OpenTrusted(request); 678 if (rv != PP_OK) 679 return ReportError("Trusted request with custom referrer", rv); 680 } 681 // Trusted requests with custom transfer encodings should succeed. 682 { 683 pp::URLRequestInfo request(instance_); 684 request.SetCustomContentTransferEncoding("foo"); 685 686 int32_t rv = OpenTrusted(request); 687 if (rv != PP_OK) 688 return ReportError( 689 "Trusted request with content-transfer-encoding failed", rv); 690 } 691 692 PASS(); 693 } 694 695 // This test should cause a redirect and ensure that the loader follows it. 696 std::string TestURLLoader::TestFollowURLRedirect() { 697 pp::URLRequestInfo request(instance_); 698 // This prefix causes the test server to return a 301 redirect. 699 std::string redirect_prefix("/server-redirect?"); 700 // We need an absolute path for the redirect to actually work. 701 std::string redirect_url = 702 GetReachableAbsoluteURL("test_url_loader_data/hello.txt"); 703 request.SetURL(redirect_prefix.append(redirect_url)); 704 return LoadAndCompareBody(request, "hello\n"); 705 } 706 707 // This test should cause a redirect and ensure that the loader runs 708 // the callback, rather than following the redirect. 709 std::string TestURLLoader::TestAuditURLRedirect() { 710 pp::URLRequestInfo request(instance_); 711 // This path will cause the server to return a 301 redirect. 712 // This prefix causes the test server to return a 301 redirect. 713 std::string redirect_prefix("/server-redirect?"); 714 // We need an absolute path for the redirect to actually work. 715 std::string redirect_url = 716 GetReachableAbsoluteURL("test_url_loader_data/hello.txt"); 717 request.SetURL(redirect_prefix.append(redirect_url)); 718 request.SetFollowRedirects(false); 719 720 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 721 722 pp::URLLoader loader(instance_); 723 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 724 CHECK_CALLBACK_BEHAVIOR(callback); 725 ASSERT_EQ(PP_OK, callback.result()); 726 727 // Checks that the response indicates a redirect, and that the URL 728 // is correct. 729 pp::URLResponseInfo response_info(loader.GetResponseInfo()); 730 if (response_info.is_null()) 731 return "URLLoader::GetResponseInfo returned null"; 732 int32_t status_code = response_info.GetStatusCode(); 733 if (status_code != 301) 734 return "Response status should be 301"; 735 736 // Test that the paused loader can be resumed. 737 callback.WaitForResult(loader.FollowRedirect(callback.GetCallback())); 738 CHECK_CALLBACK_BEHAVIOR(callback); 739 ASSERT_EQ(PP_OK, callback.result()); 740 std::string body; 741 std::string error = ReadEntireResponseBody(&loader, &body); 742 if (!error.empty()) 743 return error; 744 745 if (body != "hello\n") 746 return "URLLoader::FollowRedirect failed"; 747 748 PASS(); 749 } 750 751 std::string TestURLLoader::TestAbortCalls() { 752 pp::URLRequestInfo request(instance_); 753 request.SetURL("test_url_loader_data/hello.txt"); 754 755 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 756 int32_t rv; 757 758 // Abort |Open()|. 759 { 760 rv = pp::URLLoader(instance_).Open(request, callback.GetCallback()); 761 } 762 callback.WaitForAbortResult(rv); 763 CHECK_CALLBACK_BEHAVIOR(callback); 764 765 // Abort |ReadResponseBody()|. 766 { 767 char buf[2] = { 0 }; 768 { 769 pp::URLLoader loader(instance_); 770 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 771 CHECK_CALLBACK_BEHAVIOR(callback); 772 ASSERT_EQ(PP_OK, callback.result()); 773 774 rv = loader.ReadResponseBody(buf, sizeof(buf), callback.GetCallback()); 775 } // Destroy |loader|. 776 callback.WaitForAbortResult(rv); 777 CHECK_CALLBACK_BEHAVIOR(callback); 778 if (rv == PP_OK_COMPLETIONPENDING) { 779 if (buf[0] || buf[1]) { 780 return "URLLoader::ReadResponseBody wrote data after resource " 781 "destruction."; 782 } 783 } 784 } 785 786 // TODO(viettrungluu): More abort tests (but add basic tests first). 787 // Also test that Close() aborts properly. crbug.com/69457 788 789 PASS(); 790 } 791 792 std::string TestURLLoader::TestUntendedLoad() { 793 pp::URLRequestInfo request(instance_); 794 request.SetURL("test_url_loader_data/hello.txt"); 795 request.SetRecordDownloadProgress(true); 796 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 797 798 pp::URLLoader loader(instance_); 799 callback.WaitForResult(loader.Open(request, callback.GetCallback())); 800 CHECK_CALLBACK_BEHAVIOR(callback); 801 ASSERT_EQ(PP_OK, callback.result()); 802 803 // We received the response callback. Yield until the network code has called 804 // the loader's didReceiveData and didFinishLoading methods before we give it 805 // another callback function, to make sure the loader works with no callback. 806 int64_t bytes_received = 0; 807 int64_t total_bytes_to_be_received = 0; 808 while (true) { 809 loader.GetDownloadProgress(&bytes_received, &total_bytes_to_be_received); 810 if (total_bytes_to_be_received <= 0) 811 return ReportError("URLLoader::GetDownloadProgress total size", 812 total_bytes_to_be_received); 813 if (bytes_received == total_bytes_to_be_received) 814 break; 815 // Yield if we're on the main thread, so that URLLoader can receive more 816 // data. 817 if (pp::Module::Get()->core()->IsMainThread()) { 818 NestedEvent event(instance_->pp_instance()); 819 event.PostSignal(10); 820 event.Wait(); 821 } 822 } 823 // The loader should now have the data and have finished successfully. 824 std::string body; 825 std::string error = ReadEntireResponseBody(&loader, &body); 826 if (!error.empty()) 827 return error; 828 if (body != "hello\n") 829 return ReportError("Couldn't read data", callback.result()); 830 831 PASS(); 832 } 833 834 int32_t TestURLLoader::OpenWithPrefetchBufferThreshold(int32_t lower, 835 int32_t upper) { 836 pp::URLRequestInfo request(instance_); 837 request.SetURL("test_url_loader_data/hello.txt"); 838 request.SetPrefetchBufferLowerThreshold(lower); 839 request.SetPrefetchBufferUpperThreshold(upper); 840 841 return OpenUntrusted(request); 842 } 843 844 std::string TestURLLoader::TestPrefetchBufferThreshold() { 845 int32_t rv = OpenWithPrefetchBufferThreshold(-1, 1); 846 if (rv != PP_ERROR_FAILED) { 847 return ReportError("The prefetch limits contained a negative value but " 848 "the URLLoader did not fail.", rv); 849 } 850 851 rv = OpenWithPrefetchBufferThreshold(0, 1); 852 if (rv != PP_OK) { 853 return ReportError("The prefetch buffer limits were legal values but " 854 "the URLLoader failed.", rv); 855 } 856 857 rv = OpenWithPrefetchBufferThreshold(1000, 1); 858 if (rv != PP_ERROR_FAILED) { 859 return ReportError("The lower buffer value was higher than the upper but " 860 "the URLLoader did not fail.", rv); 861 } 862 863 PASS(); 864 } 865 866 // TODO(viettrungluu): Add tests for Get{Upload,Download}Progress, Close 867 // (including abort tests if applicable). 868