1 /* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #include "public/platform/Platform.h" 34 #include "public/platform/WebString.h" 35 #include "public/platform/WebThread.h" 36 #include "public/platform/WebURL.h" 37 #include "public/platform/WebURLLoader.h" 38 #include "public/platform/WebURLLoaderClient.h" 39 #include "public/platform/WebURLRequest.h" 40 #include "public/platform/WebURLResponse.h" 41 #include "public/platform/WebUnitTestSupport.h" 42 #include "public/web/WebFrame.h" 43 #include "public/web/WebURLLoaderOptions.h" 44 #include "public/web/WebView.h" 45 #include "web/tests/FrameTestHelpers.h" 46 #include "web/tests/URLTestHelpers.h" 47 #include "wtf/text/CString.h" 48 #include "wtf/text/WTFString.h" 49 50 #include <gtest/gtest.h> 51 52 using namespace blink; 53 using blink::URLTestHelpers::toKURL; 54 55 namespace { 56 57 class AssociatedURLLoaderTest : public testing::Test, 58 public WebURLLoaderClient { 59 public: 60 AssociatedURLLoaderTest() 61 : m_willSendRequest(false) 62 , m_didSendData(false) 63 , m_didReceiveResponse(false) 64 , m_didReceiveData(false) 65 , m_didReceiveCachedMetadata(false) 66 , m_didFinishLoading(false) 67 , m_didFail(false) 68 , m_runningMessageLoop(false) 69 { 70 // Reuse one of the test files from WebFrameTest. 71 m_baseFilePath = Platform::current()->unitTestSupport()->webKitRootDir(); 72 m_baseFilePath.append("/Source/web/tests/data/"); 73 m_frameFilePath = m_baseFilePath; 74 m_frameFilePath.append("iframes_test.html"); 75 } 76 77 WebCore::KURL RegisterMockedUrl(const std::string& urlRoot, const WTF::String& filename) 78 { 79 WebURLResponse response; 80 response.initialize(); 81 response.setMIMEType("text/html"); 82 WTF::String localPath = m_baseFilePath; 83 localPath.append(filename); 84 WebCore::KURL url = toKURL(urlRoot + filename.utf8().data()); 85 Platform::current()->unitTestSupport()->registerMockedURL(url, response, localPath); 86 return url; 87 } 88 89 void SetUp() 90 { 91 m_helper.initialize(); 92 93 std::string urlRoot = "http://www.test.com/"; 94 WebCore::KURL url = RegisterMockedUrl(urlRoot, "iframes_test.html"); 95 const char* iframeSupportFiles[] = { 96 "invisible_iframe.html", 97 "visible_iframe.html", 98 "zero_sized_iframe.html", 99 }; 100 for (size_t i = 0; i < arraysize(iframeSupportFiles); ++i) { 101 RegisterMockedUrl(urlRoot, iframeSupportFiles[i]); 102 } 103 104 FrameTestHelpers::loadFrame(mainFrame(), url.string().utf8().data()); 105 106 Platform::current()->unitTestSupport()->unregisterMockedURL(url); 107 } 108 109 void TearDown() 110 { 111 Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); 112 } 113 114 void serveRequests() 115 { 116 Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests(); 117 } 118 119 PassOwnPtr<WebURLLoader> createAssociatedURLLoader(const WebURLLoaderOptions options = WebURLLoaderOptions()) 120 { 121 return adoptPtr(mainFrame()->createAssociatedURLLoader(options)); 122 } 123 124 // WebURLLoaderClient implementation. 125 void willSendRequest(WebURLLoader* loader, WebURLRequest& newRequest, const WebURLResponse& redirectResponse) 126 { 127 m_willSendRequest = true; 128 EXPECT_EQ(m_expectedLoader, loader); 129 EXPECT_EQ(m_expectedNewRequest.url(), newRequest.url()); 130 // Check that CORS simple headers are transferred to the new request. 131 EXPECT_EQ(m_expectedNewRequest.httpHeaderField("accept"), newRequest.httpHeaderField("accept")); 132 EXPECT_EQ(m_expectedRedirectResponse.url(), redirectResponse.url()); 133 EXPECT_EQ(m_expectedRedirectResponse.httpStatusCode(), redirectResponse.httpStatusCode()); 134 EXPECT_EQ(m_expectedRedirectResponse.mimeType(), redirectResponse.mimeType()); 135 } 136 137 void didSendData(WebURLLoader* loader, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) 138 { 139 m_didSendData = true; 140 EXPECT_EQ(m_expectedLoader, loader); 141 } 142 143 void didReceiveResponse(WebURLLoader* loader, const WebURLResponse& response) 144 { 145 m_didReceiveResponse = true; 146 m_actualResponse = WebURLResponse(response); 147 EXPECT_EQ(m_expectedLoader, loader); 148 EXPECT_EQ(m_expectedResponse.url(), response.url()); 149 EXPECT_EQ(m_expectedResponse.httpStatusCode(), response.httpStatusCode()); 150 } 151 152 void didDownloadData(WebURLLoader* loader, int dataLength, int encodedDataLength) 153 { 154 m_didDownloadData = true; 155 EXPECT_EQ(m_expectedLoader, loader); 156 } 157 158 void didReceiveData(WebURLLoader* loader, const char* data, int dataLength, int encodedDataLength) 159 { 160 m_didReceiveData = true; 161 EXPECT_EQ(m_expectedLoader, loader); 162 EXPECT_TRUE(data); 163 EXPECT_GT(dataLength, 0); 164 } 165 166 void didReceiveCachedMetadata(WebURLLoader* loader, const char* data, int dataLength) 167 { 168 m_didReceiveCachedMetadata = true; 169 EXPECT_EQ(m_expectedLoader, loader); 170 } 171 172 void didFinishLoading(WebURLLoader* loader, double finishTime, int64_t encodedDataLength) 173 { 174 m_didFinishLoading = true; 175 EXPECT_EQ(m_expectedLoader, loader); 176 } 177 178 void didFail(WebURLLoader* loader, const WebURLError& error) 179 { 180 m_didFail = true; 181 EXPECT_EQ(m_expectedLoader, loader); 182 if (m_runningMessageLoop) { 183 m_runningMessageLoop = false; 184 Platform::current()->currentThread()->exitRunLoop(); 185 } 186 } 187 188 void CheckMethodFails(const char* unsafeMethod) 189 { 190 WebURLRequest request; 191 request.initialize(); 192 request.setURL(toKURL("http://www.test.com/success.html")); 193 request.setHTTPMethod(WebString::fromUTF8(unsafeMethod)); 194 WebURLLoaderOptions options; 195 options.untrustedHTTP = true; 196 CheckFails(request, options); 197 } 198 199 void CheckHeaderFails(const char* headerField) 200 { 201 CheckHeaderFails(headerField, "foo"); 202 } 203 204 void CheckHeaderFails(const char* headerField, const char* headerValue) 205 { 206 WebURLRequest request; 207 request.initialize(); 208 request.setURL(toKURL("http://www.test.com/success.html")); 209 if (equalIgnoringCase(WebString::fromUTF8(headerField), "referer")) 210 request.setHTTPReferrer(WebString::fromUTF8(headerValue), blink::WebReferrerPolicyDefault); 211 else 212 request.setHTTPHeaderField(WebString::fromUTF8(headerField), WebString::fromUTF8(headerValue)); 213 WebURLLoaderOptions options; 214 options.untrustedHTTP = true; 215 CheckFails(request, options); 216 } 217 218 void CheckFails(const WebURLRequest& request, WebURLLoaderOptions options = WebURLLoaderOptions()) 219 { 220 m_expectedLoader = createAssociatedURLLoader(options); 221 EXPECT_TRUE(m_expectedLoader); 222 m_didFail = false; 223 m_expectedLoader->loadAsynchronously(request, this); 224 // Failure should not be reported synchronously. 225 EXPECT_FALSE(m_didFail); 226 // Allow the loader to return the error. 227 m_runningMessageLoop = true; 228 Platform::current()->currentThread()->enterRunLoop(); 229 EXPECT_TRUE(m_didFail); 230 EXPECT_FALSE(m_didReceiveResponse); 231 } 232 233 bool CheckAccessControlHeaders(const char* headerName, bool exposed) 234 { 235 std::string id("http://www.other.com/CheckAccessControlExposeHeaders_"); 236 id.append(headerName); 237 if (exposed) 238 id.append("-Exposed"); 239 id.append(".html"); 240 241 WebCore::KURL url = toKURL(id); 242 WebURLRequest request; 243 request.initialize(); 244 request.setURL(url); 245 246 WebString headerNameString(WebString::fromUTF8(headerName)); 247 m_expectedResponse = WebURLResponse(); 248 m_expectedResponse.initialize(); 249 m_expectedResponse.setMIMEType("text/html"); 250 m_expectedResponse.setHTTPStatusCode(200); 251 m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*"); 252 if (exposed) 253 m_expectedResponse.addHTTPHeaderField("access-control-expose-headers", headerNameString); 254 m_expectedResponse.addHTTPHeaderField(headerNameString, "foo"); 255 Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath); 256 257 WebURLLoaderOptions options; 258 options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; 259 m_expectedLoader = createAssociatedURLLoader(options); 260 EXPECT_TRUE(m_expectedLoader); 261 m_expectedLoader->loadAsynchronously(request, this); 262 serveRequests(); 263 EXPECT_TRUE(m_didReceiveResponse); 264 EXPECT_TRUE(m_didReceiveData); 265 EXPECT_TRUE(m_didFinishLoading); 266 267 return !m_actualResponse.httpHeaderField(headerNameString).isEmpty(); 268 } 269 270 WebFrame* mainFrame() const { return m_helper.webView()->mainFrame(); } 271 272 protected: 273 WTF::String m_baseFilePath; 274 WTF::String m_frameFilePath; 275 FrameTestHelpers::WebViewHelper m_helper; 276 277 OwnPtr<WebURLLoader> m_expectedLoader; 278 WebURLResponse m_actualResponse; 279 WebURLResponse m_expectedResponse; 280 WebURLRequest m_expectedNewRequest; 281 WebURLResponse m_expectedRedirectResponse; 282 bool m_willSendRequest; 283 bool m_didSendData; 284 bool m_didReceiveResponse; 285 bool m_didDownloadData; 286 bool m_didReceiveData; 287 bool m_didReceiveCachedMetadata; 288 bool m_didFinishLoading; 289 bool m_didFail; 290 bool m_runningMessageLoop; 291 }; 292 293 // Test a successful same-origin URL load. 294 TEST_F(AssociatedURLLoaderTest, SameOriginSuccess) 295 { 296 WebCore::KURL url = toKURL("http://www.test.com/SameOriginSuccess.html"); 297 WebURLRequest request; 298 request.initialize(); 299 request.setURL(url); 300 301 m_expectedResponse = WebURLResponse(); 302 m_expectedResponse.initialize(); 303 m_expectedResponse.setMIMEType("text/html"); 304 m_expectedResponse.setHTTPStatusCode(200); 305 Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath); 306 307 m_expectedLoader = createAssociatedURLLoader(); 308 EXPECT_TRUE(m_expectedLoader); 309 m_expectedLoader->loadAsynchronously(request, this); 310 serveRequests(); 311 EXPECT_TRUE(m_didReceiveResponse); 312 EXPECT_TRUE(m_didReceiveData); 313 EXPECT_TRUE(m_didFinishLoading); 314 } 315 316 // Test that the same-origin restriction is the default. 317 TEST_F(AssociatedURLLoaderTest, SameOriginRestriction) 318 { 319 // This is cross-origin since the frame was loaded from www.test.com. 320 WebCore::KURL url = toKURL("http://www.other.com/SameOriginRestriction.html"); 321 WebURLRequest request; 322 request.initialize(); 323 request.setURL(url); 324 CheckFails(request); 325 } 326 327 // Test a successful cross-origin load. 328 TEST_F(AssociatedURLLoaderTest, CrossOriginSuccess) 329 { 330 // This is cross-origin since the frame was loaded from www.test.com. 331 WebCore::KURL url = toKURL("http://www.other.com/CrossOriginSuccess.html"); 332 WebURLRequest request; 333 request.initialize(); 334 request.setURL(url); 335 336 m_expectedResponse = WebURLResponse(); 337 m_expectedResponse.initialize(); 338 m_expectedResponse.setMIMEType("text/html"); 339 m_expectedResponse.setHTTPStatusCode(200); 340 Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath); 341 342 WebURLLoaderOptions options; 343 options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyAllow; 344 m_expectedLoader = createAssociatedURLLoader(options); 345 EXPECT_TRUE(m_expectedLoader); 346 m_expectedLoader->loadAsynchronously(request, this); 347 serveRequests(); 348 EXPECT_TRUE(m_didReceiveResponse); 349 EXPECT_TRUE(m_didReceiveData); 350 EXPECT_TRUE(m_didFinishLoading); 351 } 352 353 // Test a successful cross-origin load using CORS. 354 TEST_F(AssociatedURLLoaderTest, CrossOriginWithAccessControlSuccess) 355 { 356 // This is cross-origin since the frame was loaded from www.test.com. 357 WebCore::KURL url = toKURL("http://www.other.com/CrossOriginWithAccessControlSuccess.html"); 358 WebURLRequest request; 359 request.initialize(); 360 request.setURL(url); 361 362 m_expectedResponse = WebURLResponse(); 363 m_expectedResponse.initialize(); 364 m_expectedResponse.setMIMEType("text/html"); 365 m_expectedResponse.setHTTPStatusCode(200); 366 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); 367 Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath); 368 369 WebURLLoaderOptions options; 370 options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; 371 m_expectedLoader = createAssociatedURLLoader(options); 372 EXPECT_TRUE(m_expectedLoader); 373 m_expectedLoader->loadAsynchronously(request, this); 374 serveRequests(); 375 EXPECT_TRUE(m_didReceiveResponse); 376 EXPECT_TRUE(m_didReceiveData); 377 EXPECT_TRUE(m_didFinishLoading); 378 } 379 380 // Test an unsuccessful cross-origin load using CORS. 381 TEST_F(AssociatedURLLoaderTest, CrossOriginWithAccessControlFailure) 382 { 383 // This is cross-origin since the frame was loaded from www.test.com. 384 WebCore::KURL url = toKURL("http://www.other.com/CrossOriginWithAccessControlFailure.html"); 385 WebURLRequest request; 386 request.initialize(); 387 request.setURL(url); 388 389 m_expectedResponse = WebURLResponse(); 390 m_expectedResponse.initialize(); 391 m_expectedResponse.setMIMEType("text/html"); 392 m_expectedResponse.setHTTPStatusCode(200); 393 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); 394 Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath); 395 396 WebURLLoaderOptions options; 397 // Send credentials. This will cause the CORS checks to fail, because credentials can't be 398 // sent to a server which returns the header "access-control-allow-origin" with "*" as its value. 399 options.allowCredentials = true; 400 options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; 401 m_expectedLoader = createAssociatedURLLoader(options); 402 EXPECT_TRUE(m_expectedLoader); 403 m_expectedLoader->loadAsynchronously(request, this); 404 405 // Failure should not be reported synchronously. 406 EXPECT_FALSE(m_didFail); 407 // The loader needs to receive the response, before doing the CORS check. 408 serveRequests(); 409 EXPECT_TRUE(m_didFail); 410 EXPECT_FALSE(m_didReceiveResponse); 411 } 412 413 // Test an unsuccessful cross-origin load using CORS. 414 TEST_F(AssociatedURLLoaderTest, CrossOriginWithAccessControlFailureBadStatusCode) 415 { 416 // This is cross-origin since the frame was loaded from www.test.com. 417 WebCore::KURL url = toKURL("http://www.other.com/CrossOriginWithAccessControlFailure.html"); 418 WebURLRequest request; 419 request.initialize(); 420 request.setURL(url); 421 422 m_expectedResponse = WebURLResponse(); 423 m_expectedResponse.initialize(); 424 m_expectedResponse.setMIMEType("text/html"); 425 m_expectedResponse.setHTTPStatusCode(0); 426 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); 427 Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath); 428 429 WebURLLoaderOptions options; 430 options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; 431 m_expectedLoader = createAssociatedURLLoader(options); 432 EXPECT_TRUE(m_expectedLoader); 433 m_expectedLoader->loadAsynchronously(request, this); 434 435 // Failure should not be reported synchronously. 436 EXPECT_FALSE(m_didFail); 437 // The loader needs to receive the response, before doing the CORS check. 438 serveRequests(); 439 EXPECT_TRUE(m_didFail); 440 EXPECT_FALSE(m_didReceiveResponse); 441 } 442 443 // Test a same-origin URL redirect and load. 444 TEST_F(AssociatedURLLoaderTest, RedirectSuccess) 445 { 446 WebCore::KURL url = toKURL("http://www.test.com/RedirectSuccess.html"); 447 char redirect[] = "http://www.test.com/RedirectSuccess2.html"; // Same-origin 448 WebCore::KURL redirectURL = toKURL(redirect); 449 450 WebURLRequest request; 451 request.initialize(); 452 request.setURL(url); 453 454 m_expectedRedirectResponse = WebURLResponse(); 455 m_expectedRedirectResponse.initialize(); 456 m_expectedRedirectResponse.setMIMEType("text/html"); 457 m_expectedRedirectResponse.setHTTPStatusCode(301); 458 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); 459 Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedRedirectResponse, m_frameFilePath); 460 461 m_expectedNewRequest = WebURLRequest(); 462 m_expectedNewRequest.initialize(); 463 m_expectedNewRequest.setURL(redirectURL); 464 465 m_expectedResponse = WebURLResponse(); 466 m_expectedResponse.initialize(); 467 m_expectedResponse.setMIMEType("text/html"); 468 m_expectedResponse.setHTTPStatusCode(200); 469 Platform::current()->unitTestSupport()->registerMockedURL(redirectURL, m_expectedResponse, m_frameFilePath); 470 471 m_expectedLoader = createAssociatedURLLoader(); 472 EXPECT_TRUE(m_expectedLoader); 473 m_expectedLoader->loadAsynchronously(request, this); 474 serveRequests(); 475 EXPECT_TRUE(m_willSendRequest); 476 EXPECT_TRUE(m_didReceiveResponse); 477 EXPECT_TRUE(m_didReceiveData); 478 EXPECT_TRUE(m_didFinishLoading); 479 } 480 481 // Test that a cross origin redirect response without CORS headers fails. 482 // Disabled, http://crbug.com/240912 . 483 TEST_F(AssociatedURLLoaderTest, DISABLED_RedirectCrossOriginWithAccessControlFailure) 484 { 485 WebCore::KURL url = toKURL("http://www.test.com/RedirectCrossOriginWithAccessControlFailure.html"); 486 char redirect[] = "http://www.other.com/RedirectCrossOriginWithAccessControlFailure.html"; // Cross-origin 487 WebCore::KURL redirectURL = toKURL(redirect); 488 489 WebURLRequest request; 490 request.initialize(); 491 request.setURL(url); 492 493 // Create a redirect response without CORS headers. 494 m_expectedRedirectResponse = WebURLResponse(); 495 m_expectedRedirectResponse.initialize(); 496 m_expectedRedirectResponse.setMIMEType("text/html"); 497 m_expectedRedirectResponse.setHTTPStatusCode(301); 498 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); 499 Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedRedirectResponse, m_frameFilePath); 500 501 WebURLLoaderOptions options; 502 options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; 503 m_expectedLoader = createAssociatedURLLoader(options); 504 EXPECT_TRUE(m_expectedLoader); 505 m_expectedLoader->loadAsynchronously(request, this); 506 serveRequests(); 507 // We should not receive a notification for the redirect or any response. 508 EXPECT_FALSE(m_willSendRequest); 509 EXPECT_FALSE(m_didReceiveResponse); 510 EXPECT_FALSE(m_didReceiveData); 511 EXPECT_FALSE(m_didFail); 512 } 513 514 // Test that a cross origin redirect response with CORS headers that allow the requesting origin succeeds. 515 TEST_F(AssociatedURLLoaderTest, RedirectCrossOriginWithAccessControlSuccess) 516 { 517 WebCore::KURL url = toKURL("http://www.test.com/RedirectCrossOriginWithAccessControlSuccess.html"); 518 char redirect[] = "http://www.other.com/RedirectCrossOriginWithAccessControlSuccess.html"; // Cross-origin 519 WebCore::KURL redirectURL = toKURL(redirect); 520 521 WebURLRequest request; 522 request.initialize(); 523 request.setURL(url); 524 // Add a CORS simple header. 525 request.setHTTPHeaderField("accept", "application/json"); 526 527 // Create a redirect response that allows the redirect to pass the access control checks. 528 m_expectedRedirectResponse = WebURLResponse(); 529 m_expectedRedirectResponse.initialize(); 530 m_expectedRedirectResponse.setMIMEType("text/html"); 531 m_expectedRedirectResponse.setHTTPStatusCode(301); 532 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); 533 m_expectedRedirectResponse.addHTTPHeaderField("access-control-allow-origin", "*"); 534 Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedRedirectResponse, m_frameFilePath); 535 536 m_expectedNewRequest = WebURLRequest(); 537 m_expectedNewRequest.initialize(); 538 m_expectedNewRequest.setURL(redirectURL); 539 m_expectedNewRequest.setHTTPHeaderField("accept", "application/json"); 540 541 m_expectedResponse = WebURLResponse(); 542 m_expectedResponse.initialize(); 543 m_expectedResponse.setMIMEType("text/html"); 544 m_expectedResponse.setHTTPStatusCode(200); 545 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); 546 Platform::current()->unitTestSupport()->registerMockedURL(redirectURL, m_expectedResponse, m_frameFilePath); 547 548 WebURLLoaderOptions options; 549 options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; 550 m_expectedLoader = createAssociatedURLLoader(options); 551 EXPECT_TRUE(m_expectedLoader); 552 m_expectedLoader->loadAsynchronously(request, this); 553 serveRequests(); 554 // We should not receive a notification for the redirect. 555 EXPECT_FALSE(m_willSendRequest); 556 EXPECT_TRUE(m_didReceiveResponse); 557 EXPECT_TRUE(m_didReceiveData); 558 EXPECT_TRUE(m_didFinishLoading); 559 } 560 561 // Test that untrusted loads can't use a forbidden method. 562 TEST_F(AssociatedURLLoaderTest, UntrustedCheckMethods) 563 { 564 // Check non-token method fails. 565 CheckMethodFails("GET()"); 566 CheckMethodFails("POST\x0d\x0ax-csrf-token:\x20test1234"); 567 568 // Forbidden methods should fail regardless of casing. 569 CheckMethodFails("CoNneCt"); 570 CheckMethodFails("TrAcK"); 571 CheckMethodFails("TrAcE"); 572 } 573 574 // Test that untrusted loads can't use a forbidden header field. 575 TEST_F(AssociatedURLLoaderTest, UntrustedCheckHeaders) 576 { 577 // Check non-token header fails. 578 CheckHeaderFails("foo()"); 579 580 // Check forbidden headers fail. 581 CheckHeaderFails("accept-charset"); 582 CheckHeaderFails("accept-encoding"); 583 CheckHeaderFails("connection"); 584 CheckHeaderFails("content-length"); 585 CheckHeaderFails("cookie"); 586 CheckHeaderFails("cookie2"); 587 CheckHeaderFails("content-transfer-encoding"); 588 CheckHeaderFails("date"); 589 CheckHeaderFails("expect"); 590 CheckHeaderFails("host"); 591 CheckHeaderFails("keep-alive"); 592 CheckHeaderFails("origin"); 593 CheckHeaderFails("referer"); 594 CheckHeaderFails("te"); 595 CheckHeaderFails("trailer"); 596 CheckHeaderFails("transfer-encoding"); 597 CheckHeaderFails("upgrade"); 598 CheckHeaderFails("user-agent"); 599 CheckHeaderFails("via"); 600 601 CheckHeaderFails("proxy-"); 602 CheckHeaderFails("proxy-foo"); 603 CheckHeaderFails("sec-"); 604 CheckHeaderFails("sec-foo"); 605 606 // Check that validation is case-insensitive. 607 CheckHeaderFails("AcCePt-ChArSeT"); 608 CheckHeaderFails("ProXy-FoO"); 609 610 // Check invalid header values. 611 CheckHeaderFails("foo", "bar\x0d\x0ax-csrf-token:\x20test1234"); 612 } 613 614 // Test that the loader filters response headers according to the CORS standard. 615 TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderWhitelisting) 616 { 617 // Test that whitelisted headers are returned without exposing them. 618 EXPECT_TRUE(CheckAccessControlHeaders("cache-control", false)); 619 EXPECT_TRUE(CheckAccessControlHeaders("content-language", false)); 620 EXPECT_TRUE(CheckAccessControlHeaders("content-type", false)); 621 EXPECT_TRUE(CheckAccessControlHeaders("expires", false)); 622 EXPECT_TRUE(CheckAccessControlHeaders("last-modified", false)); 623 EXPECT_TRUE(CheckAccessControlHeaders("pragma", false)); 624 625 // Test that non-whitelisted headers aren't returned. 626 EXPECT_FALSE(CheckAccessControlHeaders("non-whitelisted", false)); 627 628 // Test that Set-Cookie headers aren't returned. 629 EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", false)); 630 EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie2", false)); 631 632 // Test that exposed headers that aren't whitelisted are returned. 633 EXPECT_TRUE(CheckAccessControlHeaders("non-whitelisted", true)); 634 635 // Test that Set-Cookie headers aren't returned, even if exposed. 636 EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", true)); 637 } 638 639 // Test that the loader can allow non-whitelisted response headers for trusted CORS loads. 640 TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderAllowResponseHeaders) 641 { 642 WebURLRequest request; 643 request.initialize(); 644 WebCore::KURL url = toKURL("http://www.other.com/CrossOriginHeaderAllowResponseHeaders.html"); 645 request.setURL(url); 646 647 WebString headerNameString(WebString::fromUTF8("non-whitelisted")); 648 m_expectedResponse = WebURLResponse(); 649 m_expectedResponse.initialize(); 650 m_expectedResponse.setMIMEType("text/html"); 651 m_expectedResponse.setHTTPStatusCode(200); 652 m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*"); 653 m_expectedResponse.addHTTPHeaderField(headerNameString, "foo"); 654 Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath); 655 656 WebURLLoaderOptions options; 657 options.exposeAllResponseHeaders = true; // This turns off response whitelisting. 658 options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; 659 m_expectedLoader = createAssociatedURLLoader(options); 660 EXPECT_TRUE(m_expectedLoader); 661 m_expectedLoader->loadAsynchronously(request, this); 662 serveRequests(); 663 EXPECT_TRUE(m_didReceiveResponse); 664 EXPECT_TRUE(m_didReceiveData); 665 EXPECT_TRUE(m_didFinishLoading); 666 667 EXPECT_FALSE(m_actualResponse.httpHeaderField(headerNameString).isEmpty()); 668 } 669 670 } 671