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