| OLD | NEW |
| (Empty) |
| 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 "platform/testing/URLTestHelpers.h" | |
| 32 #include "platform/testing/UnitTestHelpers.h" | |
| 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/WebURLLoaderMockFactory.h" | |
| 40 #include "public/platform/WebURLRequest.h" | |
| 41 #include "public/platform/WebURLResponse.h" | |
| 42 #include "public/web/WebCache.h" | |
| 43 #include "public/web/WebFrame.h" | |
| 44 #include "public/web/WebURLLoaderOptions.h" | |
| 45 #include "public/web/WebView.h" | |
| 46 #include "testing/gtest/include/gtest/gtest.h" | |
| 47 #include "web/tests/FrameTestHelpers.h" | |
| 48 #include "wtf/PtrUtil.h" | |
| 49 #include "wtf/text/CString.h" | |
| 50 #include "wtf/text/WTFString.h" | |
| 51 #include <memory> | |
| 52 | |
| 53 using blink::URLTestHelpers::toKURL; | |
| 54 using blink::testing::runPendingTasks; | |
| 55 | |
| 56 namespace blink { | |
| 57 | |
| 58 class AssociatedURLLoaderTest : public ::testing::Test, | |
| 59 public WebURLLoaderClient { | |
| 60 public: | |
| 61 AssociatedURLLoaderTest() | |
| 62 : m_willFollowRedirect(false), | |
| 63 m_didSendData(false), | |
| 64 m_didReceiveResponse(false), | |
| 65 m_didReceiveData(false), | |
| 66 m_didReceiveCachedMetadata(false), | |
| 67 m_didFinishLoading(false), | |
| 68 m_didFail(false) { | |
| 69 // Reuse one of the test files from WebFrameTest. | |
| 70 m_baseFilePath = testing::blinkRootDir(); | |
| 71 m_baseFilePath.append("/Source/web/tests/data/"); | |
| 72 m_frameFilePath = m_baseFilePath; | |
| 73 m_frameFilePath.append("iframes_test.html"); | |
| 74 } | |
| 75 | |
| 76 KURL RegisterMockedUrl(const std::string& urlRoot, | |
| 77 const WTF::String& filename) { | |
| 78 WebURLResponse response; | |
| 79 response.setMIMEType("text/html"); | |
| 80 WTF::String localPath = m_baseFilePath; | |
| 81 localPath.append(filename); | |
| 82 KURL url = toKURL(urlRoot + filename.utf8().data()); | |
| 83 Platform::current()->getURLLoaderMockFactory()->registerURL(url, response, | |
| 84 localPath); | |
| 85 return url; | |
| 86 } | |
| 87 | |
| 88 void SetUp() override { | |
| 89 m_helper.initialize(); | |
| 90 | |
| 91 std::string urlRoot = "http://www.test.com/"; | |
| 92 KURL url = RegisterMockedUrl(urlRoot, "iframes_test.html"); | |
| 93 const char* iframeSupportFiles[] = { | |
| 94 "invisible_iframe.html", "visible_iframe.html", | |
| 95 "zero_sized_iframe.html", | |
| 96 }; | |
| 97 for (size_t i = 0; i < WTF_ARRAY_LENGTH(iframeSupportFiles); ++i) { | |
| 98 RegisterMockedUrl(urlRoot, iframeSupportFiles[i]); | |
| 99 } | |
| 100 | |
| 101 FrameTestHelpers::loadFrame(mainFrame(), url.getString().utf8().data()); | |
| 102 | |
| 103 Platform::current()->getURLLoaderMockFactory()->unregisterURL(url); | |
| 104 } | |
| 105 | |
| 106 void TearDown() override { | |
| 107 Platform::current()->getURLLoaderMockFactory()->unregisterAllURLs(); | |
| 108 WebCache::clear(); | |
| 109 } | |
| 110 | |
| 111 void serveRequests() { | |
| 112 Platform::current()->getURLLoaderMockFactory()->serveAsynchronousRequests(); | |
| 113 } | |
| 114 | |
| 115 std::unique_ptr<WebURLLoader> createAssociatedURLLoader( | |
| 116 const WebURLLoaderOptions options = WebURLLoaderOptions()) { | |
| 117 return wrapUnique(mainFrame()->createAssociatedURLLoader(options)); | |
| 118 } | |
| 119 | |
| 120 // WebURLLoaderClient implementation. | |
| 121 bool willFollowRedirect(WebURLLoader* loader, | |
| 122 WebURLRequest& newRequest, | |
| 123 const WebURLResponse& redirectResponse) override { | |
| 124 m_willFollowRedirect = true; | |
| 125 EXPECT_EQ(m_expectedLoader.get(), loader); | |
| 126 EXPECT_EQ(m_expectedNewRequest.url(), newRequest.url()); | |
| 127 // Check that CORS simple headers are transferred to the new request. | |
| 128 EXPECT_EQ(m_expectedNewRequest.httpHeaderField("accept"), | |
| 129 newRequest.httpHeaderField("accept")); | |
| 130 EXPECT_EQ(m_expectedRedirectResponse.url(), redirectResponse.url()); | |
| 131 EXPECT_EQ(m_expectedRedirectResponse.httpStatusCode(), | |
| 132 redirectResponse.httpStatusCode()); | |
| 133 EXPECT_EQ(m_expectedRedirectResponse.mimeType(), | |
| 134 redirectResponse.mimeType()); | |
| 135 return true; | |
| 136 } | |
| 137 | |
| 138 void didSendData(WebURLLoader* loader, | |
| 139 unsigned long long bytesSent, | |
| 140 unsigned long long totalBytesToBeSent) override { | |
| 141 m_didSendData = true; | |
| 142 EXPECT_EQ(m_expectedLoader.get(), loader); | |
| 143 } | |
| 144 | |
| 145 void didReceiveResponse(WebURLLoader* loader, | |
| 146 const WebURLResponse& response) override { | |
| 147 m_didReceiveResponse = true; | |
| 148 m_actualResponse = WebURLResponse(response); | |
| 149 EXPECT_EQ(m_expectedLoader.get(), loader); | |
| 150 EXPECT_EQ(m_expectedResponse.url(), response.url()); | |
| 151 EXPECT_EQ(m_expectedResponse.httpStatusCode(), response.httpStatusCode()); | |
| 152 } | |
| 153 | |
| 154 void didDownloadData(WebURLLoader* loader, | |
| 155 int dataLength, | |
| 156 int encodedDataLength) override { | |
| 157 m_didDownloadData = true; | |
| 158 EXPECT_EQ(m_expectedLoader.get(), loader); | |
| 159 } | |
| 160 | |
| 161 void didReceiveData(WebURLLoader* loader, | |
| 162 const char* data, | |
| 163 int dataLength, | |
| 164 int encodedDataLength, | |
| 165 int encodedBodyLength) override { | |
| 166 m_didReceiveData = true; | |
| 167 EXPECT_EQ(m_expectedLoader.get(), loader); | |
| 168 EXPECT_TRUE(data); | |
| 169 EXPECT_GT(dataLength, 0); | |
| 170 } | |
| 171 | |
| 172 void didReceiveCachedMetadata(WebURLLoader* loader, | |
| 173 const char* data, | |
| 174 int dataLength) override { | |
| 175 m_didReceiveCachedMetadata = true; | |
| 176 EXPECT_EQ(m_expectedLoader.get(), loader); | |
| 177 } | |
| 178 | |
| 179 void didFinishLoading(WebURLLoader* loader, | |
| 180 double finishTime, | |
| 181 int64_t encodedDataLength) override { | |
| 182 m_didFinishLoading = true; | |
| 183 EXPECT_EQ(m_expectedLoader.get(), loader); | |
| 184 } | |
| 185 | |
| 186 void didFail(WebURLLoader* loader, const WebURLError& error) override { | |
| 187 m_didFail = true; | |
| 188 EXPECT_EQ(m_expectedLoader.get(), loader); | |
| 189 } | |
| 190 | |
| 191 void CheckMethodFails(const char* unsafeMethod) { | |
| 192 WebURLRequest request; | |
| 193 request.setURL(toKURL("http://www.test.com/success.html")); | |
| 194 request.setHTTPMethod(WebString::fromUTF8(unsafeMethod)); | |
| 195 WebURLLoaderOptions options; | |
| 196 options.untrustedHTTP = true; | |
| 197 CheckFails(request, options); | |
| 198 } | |
| 199 | |
| 200 void CheckHeaderFails(const char* headerField) { | |
| 201 CheckHeaderFails(headerField, "foo"); | |
| 202 } | |
| 203 | |
| 204 void CheckHeaderFails(const char* headerField, const char* headerValue) { | |
| 205 WebURLRequest request; | |
| 206 request.setURL(toKURL("http://www.test.com/success.html")); | |
| 207 if (equalIgnoringASCIICase(WebString::fromUTF8(headerField), "referer")) | |
| 208 request.setHTTPReferrer(WebString::fromUTF8(headerValue), | |
| 209 WebReferrerPolicyDefault); | |
| 210 else | |
| 211 request.setHTTPHeaderField(WebString::fromUTF8(headerField), | |
| 212 WebString::fromUTF8(headerValue)); | |
| 213 WebURLLoaderOptions options; | |
| 214 options.untrustedHTTP = true; | |
| 215 CheckFails(request, options); | |
| 216 } | |
| 217 | |
| 218 void CheckFails(const WebURLRequest& request, | |
| 219 WebURLLoaderOptions options = WebURLLoaderOptions()) { | |
| 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 runPendingTasks(); | |
| 228 EXPECT_TRUE(m_didFail); | |
| 229 EXPECT_FALSE(m_didReceiveResponse); | |
| 230 } | |
| 231 | |
| 232 bool CheckAccessControlHeaders(const char* headerName, bool exposed) { | |
| 233 std::string id("http://www.other.com/CheckAccessControlExposeHeaders_"); | |
| 234 id.append(headerName); | |
| 235 if (exposed) | |
| 236 id.append("-Exposed"); | |
| 237 id.append(".html"); | |
| 238 | |
| 239 KURL url = toKURL(id); | |
| 240 WebURLRequest request; | |
| 241 request.setURL(url); | |
| 242 | |
| 243 WebString headerNameString(WebString::fromUTF8(headerName)); | |
| 244 m_expectedResponse = WebURLResponse(); | |
| 245 m_expectedResponse.setMIMEType("text/html"); | |
| 246 m_expectedResponse.setHTTPStatusCode(200); | |
| 247 m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*"); | |
| 248 if (exposed) | |
| 249 m_expectedResponse.addHTTPHeaderField("access-control-expose-headers", | |
| 250 headerNameString); | |
| 251 m_expectedResponse.addHTTPHeaderField(headerNameString, "foo"); | |
| 252 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 253 url, m_expectedResponse, m_frameFilePath); | |
| 254 | |
| 255 WebURLLoaderOptions options; | |
| 256 options.crossOriginRequestPolicy = | |
| 257 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
| 258 m_expectedLoader = createAssociatedURLLoader(options); | |
| 259 EXPECT_TRUE(m_expectedLoader); | |
| 260 m_expectedLoader->loadAsynchronously(request, this); | |
| 261 serveRequests(); | |
| 262 EXPECT_TRUE(m_didReceiveResponse); | |
| 263 EXPECT_TRUE(m_didReceiveData); | |
| 264 EXPECT_TRUE(m_didFinishLoading); | |
| 265 | |
| 266 return !m_actualResponse.httpHeaderField(headerNameString).isEmpty(); | |
| 267 } | |
| 268 | |
| 269 WebFrame* mainFrame() const { return m_helper.webView()->mainFrame(); } | |
| 270 | |
| 271 protected: | |
| 272 String m_baseFilePath; | |
| 273 String m_frameFilePath; | |
| 274 FrameTestHelpers::WebViewHelper m_helper; | |
| 275 | |
| 276 std::unique_ptr<WebURLLoader> m_expectedLoader; | |
| 277 WebURLResponse m_actualResponse; | |
| 278 WebURLResponse m_expectedResponse; | |
| 279 WebURLRequest m_expectedNewRequest; | |
| 280 WebURLResponse m_expectedRedirectResponse; | |
| 281 bool m_willFollowRedirect; | |
| 282 bool m_didSendData; | |
| 283 bool m_didReceiveResponse; | |
| 284 bool m_didDownloadData; | |
| 285 bool m_didReceiveData; | |
| 286 bool m_didReceiveCachedMetadata; | |
| 287 bool m_didFinishLoading; | |
| 288 bool m_didFail; | |
| 289 }; | |
| 290 | |
| 291 // Test a successful same-origin URL load. | |
| 292 TEST_F(AssociatedURLLoaderTest, SameOriginSuccess) { | |
| 293 KURL url = toKURL("http://www.test.com/SameOriginSuccess.html"); | |
| 294 WebURLRequest request; | |
| 295 request.setURL(url); | |
| 296 | |
| 297 m_expectedResponse = WebURLResponse(); | |
| 298 m_expectedResponse.setMIMEType("text/html"); | |
| 299 m_expectedResponse.setHTTPStatusCode(200); | |
| 300 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 301 url, m_expectedResponse, m_frameFilePath); | |
| 302 | |
| 303 m_expectedLoader = createAssociatedURLLoader(); | |
| 304 EXPECT_TRUE(m_expectedLoader); | |
| 305 m_expectedLoader->loadAsynchronously(request, this); | |
| 306 serveRequests(); | |
| 307 EXPECT_TRUE(m_didReceiveResponse); | |
| 308 EXPECT_TRUE(m_didReceiveData); | |
| 309 EXPECT_TRUE(m_didFinishLoading); | |
| 310 } | |
| 311 | |
| 312 // Test that the same-origin restriction is the default. | |
| 313 TEST_F(AssociatedURLLoaderTest, SameOriginRestriction) { | |
| 314 // This is cross-origin since the frame was loaded from www.test.com. | |
| 315 KURL url = toKURL("http://www.other.com/SameOriginRestriction.html"); | |
| 316 WebURLRequest request; | |
| 317 request.setURL(url); | |
| 318 CheckFails(request); | |
| 319 } | |
| 320 | |
| 321 // Test a successful cross-origin load. | |
| 322 TEST_F(AssociatedURLLoaderTest, CrossOriginSuccess) { | |
| 323 // This is cross-origin since the frame was loaded from www.test.com. | |
| 324 KURL url = toKURL("http://www.other.com/CrossOriginSuccess"); | |
| 325 WebURLRequest request; | |
| 326 request.setURL(url); | |
| 327 // No-CORS requests (CrossOriginRequestPolicyAllow) aren't allowed for the | |
| 328 // default context. So we set the context as Script here. | |
| 329 request.setRequestContext(WebURLRequest::RequestContextScript); | |
| 330 | |
| 331 m_expectedResponse = WebURLResponse(); | |
| 332 m_expectedResponse.setMIMEType("text/html"); | |
| 333 m_expectedResponse.setHTTPStatusCode(200); | |
| 334 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 335 url, m_expectedResponse, m_frameFilePath); | |
| 336 | |
| 337 WebURLLoaderOptions options; | |
| 338 options.crossOriginRequestPolicy = | |
| 339 WebURLLoaderOptions::CrossOriginRequestPolicyAllow; | |
| 340 m_expectedLoader = createAssociatedURLLoader(options); | |
| 341 EXPECT_TRUE(m_expectedLoader); | |
| 342 m_expectedLoader->loadAsynchronously(request, this); | |
| 343 serveRequests(); | |
| 344 EXPECT_TRUE(m_didReceiveResponse); | |
| 345 EXPECT_TRUE(m_didReceiveData); | |
| 346 EXPECT_TRUE(m_didFinishLoading); | |
| 347 } | |
| 348 | |
| 349 // Test a successful cross-origin load using CORS. | |
| 350 TEST_F(AssociatedURLLoaderTest, CrossOriginWithAccessControlSuccess) { | |
| 351 // This is cross-origin since the frame was loaded from www.test.com. | |
| 352 KURL url = | |
| 353 toKURL("http://www.other.com/CrossOriginWithAccessControlSuccess.html"); | |
| 354 WebURLRequest request; | |
| 355 request.setURL(url); | |
| 356 | |
| 357 m_expectedResponse = WebURLResponse(); | |
| 358 m_expectedResponse.setMIMEType("text/html"); | |
| 359 m_expectedResponse.setHTTPStatusCode(200); | |
| 360 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); | |
| 361 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 362 url, m_expectedResponse, m_frameFilePath); | |
| 363 | |
| 364 WebURLLoaderOptions options; | |
| 365 options.crossOriginRequestPolicy = | |
| 366 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
| 367 m_expectedLoader = createAssociatedURLLoader(options); | |
| 368 EXPECT_TRUE(m_expectedLoader); | |
| 369 m_expectedLoader->loadAsynchronously(request, this); | |
| 370 serveRequests(); | |
| 371 EXPECT_TRUE(m_didReceiveResponse); | |
| 372 EXPECT_TRUE(m_didReceiveData); | |
| 373 EXPECT_TRUE(m_didFinishLoading); | |
| 374 } | |
| 375 | |
| 376 // Test an unsuccessful cross-origin load using CORS. | |
| 377 TEST_F(AssociatedURLLoaderTest, CrossOriginWithAccessControlFailure) { | |
| 378 // This is cross-origin since the frame was loaded from www.test.com. | |
| 379 KURL url = | |
| 380 toKURL("http://www.other.com/CrossOriginWithAccessControlFailure.html"); | |
| 381 WebURLRequest request; | |
| 382 request.setURL(url); | |
| 383 | |
| 384 m_expectedResponse = WebURLResponse(); | |
| 385 m_expectedResponse.setMIMEType("text/html"); | |
| 386 m_expectedResponse.setHTTPStatusCode(200); | |
| 387 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); | |
| 388 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 389 url, m_expectedResponse, m_frameFilePath); | |
| 390 | |
| 391 WebURLLoaderOptions options; | |
| 392 // Send credentials. This will cause the CORS checks to fail, because | |
| 393 // credentials can't be sent to a server which returns the header | |
| 394 // "access-control-allow-origin" with "*" as its value. | |
| 395 options.allowCredentials = true; | |
| 396 options.crossOriginRequestPolicy = | |
| 397 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
| 398 m_expectedLoader = createAssociatedURLLoader(options); | |
| 399 EXPECT_TRUE(m_expectedLoader); | |
| 400 m_expectedLoader->loadAsynchronously(request, this); | |
| 401 | |
| 402 // Failure should not be reported synchronously. | |
| 403 EXPECT_FALSE(m_didFail); | |
| 404 // The loader needs to receive the response, before doing the CORS check. | |
| 405 serveRequests(); | |
| 406 EXPECT_TRUE(m_didFail); | |
| 407 EXPECT_FALSE(m_didReceiveResponse); | |
| 408 } | |
| 409 | |
| 410 // Test an unsuccessful cross-origin load using CORS. | |
| 411 TEST_F(AssociatedURLLoaderTest, | |
| 412 CrossOriginWithAccessControlFailureBadStatusCode) { | |
| 413 // This is cross-origin since the frame was loaded from www.test.com. | |
| 414 KURL url = | |
| 415 toKURL("http://www.other.com/CrossOriginWithAccessControlFailure.html"); | |
| 416 WebURLRequest request; | |
| 417 request.setURL(url); | |
| 418 | |
| 419 m_expectedResponse = WebURLResponse(); | |
| 420 m_expectedResponse.setMIMEType("text/html"); | |
| 421 m_expectedResponse.setHTTPStatusCode(0); | |
| 422 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); | |
| 423 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 424 url, m_expectedResponse, m_frameFilePath); | |
| 425 | |
| 426 WebURLLoaderOptions options; | |
| 427 options.crossOriginRequestPolicy = | |
| 428 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
| 429 m_expectedLoader = createAssociatedURLLoader(options); | |
| 430 EXPECT_TRUE(m_expectedLoader); | |
| 431 m_expectedLoader->loadAsynchronously(request, this); | |
| 432 | |
| 433 // Failure should not be reported synchronously. | |
| 434 EXPECT_FALSE(m_didFail); | |
| 435 // The loader needs to receive the response, before doing the CORS check. | |
| 436 serveRequests(); | |
| 437 EXPECT_TRUE(m_didFail); | |
| 438 EXPECT_FALSE(m_didReceiveResponse); | |
| 439 } | |
| 440 | |
| 441 // Test a same-origin URL redirect and load. | |
| 442 TEST_F(AssociatedURLLoaderTest, RedirectSuccess) { | |
| 443 KURL url = toKURL("http://www.test.com/RedirectSuccess.html"); | |
| 444 char redirect[] = "http://www.test.com/RedirectSuccess2.html"; // Same-origin | |
| 445 KURL redirectURL = toKURL(redirect); | |
| 446 | |
| 447 WebURLRequest request; | |
| 448 request.setURL(url); | |
| 449 | |
| 450 m_expectedRedirectResponse = WebURLResponse(); | |
| 451 m_expectedRedirectResponse.setMIMEType("text/html"); | |
| 452 m_expectedRedirectResponse.setHTTPStatusCode(301); | |
| 453 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); | |
| 454 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 455 url, m_expectedRedirectResponse, m_frameFilePath); | |
| 456 | |
| 457 m_expectedNewRequest = WebURLRequest(); | |
| 458 m_expectedNewRequest.setURL(redirectURL); | |
| 459 | |
| 460 m_expectedResponse = WebURLResponse(); | |
| 461 m_expectedResponse.setMIMEType("text/html"); | |
| 462 m_expectedResponse.setHTTPStatusCode(200); | |
| 463 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 464 redirectURL, m_expectedResponse, m_frameFilePath); | |
| 465 | |
| 466 m_expectedLoader = createAssociatedURLLoader(); | |
| 467 EXPECT_TRUE(m_expectedLoader); | |
| 468 m_expectedLoader->loadAsynchronously(request, this); | |
| 469 serveRequests(); | |
| 470 EXPECT_TRUE(m_willFollowRedirect); | |
| 471 EXPECT_TRUE(m_didReceiveResponse); | |
| 472 EXPECT_TRUE(m_didReceiveData); | |
| 473 EXPECT_TRUE(m_didFinishLoading); | |
| 474 } | |
| 475 | |
| 476 // Test a cross-origin URL redirect without Access Control set. | |
| 477 TEST_F(AssociatedURLLoaderTest, RedirectCrossOriginFailure) { | |
| 478 KURL url = toKURL("http://www.test.com/RedirectCrossOriginFailure.html"); | |
| 479 char redirect[] = | |
| 480 "http://www.other.com/RedirectCrossOriginFailure.html"; // Cross-origin | |
| 481 KURL redirectURL = toKURL(redirect); | |
| 482 | |
| 483 WebURLRequest request; | |
| 484 request.setURL(url); | |
| 485 | |
| 486 m_expectedRedirectResponse = WebURLResponse(); | |
| 487 m_expectedRedirectResponse.setMIMEType("text/html"); | |
| 488 m_expectedRedirectResponse.setHTTPStatusCode(301); | |
| 489 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); | |
| 490 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 491 url, m_expectedRedirectResponse, m_frameFilePath); | |
| 492 | |
| 493 m_expectedNewRequest = WebURLRequest(); | |
| 494 m_expectedNewRequest.setURL(redirectURL); | |
| 495 | |
| 496 m_expectedResponse = WebURLResponse(); | |
| 497 m_expectedResponse.setMIMEType("text/html"); | |
| 498 m_expectedResponse.setHTTPStatusCode(200); | |
| 499 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 500 redirectURL, m_expectedResponse, m_frameFilePath); | |
| 501 | |
| 502 m_expectedLoader = createAssociatedURLLoader(); | |
| 503 EXPECT_TRUE(m_expectedLoader); | |
| 504 m_expectedLoader->loadAsynchronously(request, this); | |
| 505 | |
| 506 serveRequests(); | |
| 507 EXPECT_FALSE(m_willFollowRedirect); | |
| 508 EXPECT_FALSE(m_didReceiveResponse); | |
| 509 EXPECT_FALSE(m_didReceiveData); | |
| 510 EXPECT_FALSE(m_didFinishLoading); | |
| 511 } | |
| 512 | |
| 513 // Test that a cross origin redirect response without CORS headers fails. | |
| 514 TEST_F(AssociatedURLLoaderTest, RedirectCrossOriginWithAccessControlFailure) { | |
| 515 KURL url = toKURL( | |
| 516 "http://www.test.com/RedirectCrossOriginWithAccessControlFailure.html"); | |
| 517 char redirect[] = | |
| 518 "http://www.other.com/" | |
| 519 "RedirectCrossOriginWithAccessControlFailure.html"; // Cross-origin | |
| 520 KURL redirectURL = toKURL(redirect); | |
| 521 | |
| 522 WebURLRequest request; | |
| 523 request.setURL(url); | |
| 524 | |
| 525 m_expectedRedirectResponse = WebURLResponse(); | |
| 526 m_expectedRedirectResponse.setMIMEType("text/html"); | |
| 527 m_expectedRedirectResponse.setHTTPStatusCode(301); | |
| 528 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); | |
| 529 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 530 url, m_expectedRedirectResponse, m_frameFilePath); | |
| 531 | |
| 532 m_expectedNewRequest = WebURLRequest(); | |
| 533 m_expectedNewRequest.setURL(redirectURL); | |
| 534 | |
| 535 m_expectedResponse = WebURLResponse(); | |
| 536 m_expectedResponse.setMIMEType("text/html"); | |
| 537 m_expectedResponse.setHTTPStatusCode(200); | |
| 538 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 539 redirectURL, m_expectedResponse, m_frameFilePath); | |
| 540 | |
| 541 WebURLLoaderOptions options; | |
| 542 options.crossOriginRequestPolicy = | |
| 543 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
| 544 m_expectedLoader = createAssociatedURLLoader(options); | |
| 545 EXPECT_TRUE(m_expectedLoader); | |
| 546 m_expectedLoader->loadAsynchronously(request, this); | |
| 547 | |
| 548 serveRequests(); | |
| 549 // We should get a notification about access control check failure. | |
| 550 EXPECT_FALSE(m_willFollowRedirect); | |
| 551 EXPECT_FALSE(m_didReceiveResponse); | |
| 552 EXPECT_FALSE(m_didReceiveData); | |
| 553 EXPECT_TRUE(m_didFail); | |
| 554 } | |
| 555 | |
| 556 // Test that a cross origin redirect response with CORS headers that allow the | |
| 557 // requesting origin succeeds. | |
| 558 TEST_F(AssociatedURLLoaderTest, RedirectCrossOriginWithAccessControlSuccess) { | |
| 559 KURL url = toKURL( | |
| 560 "http://www.test.com/RedirectCrossOriginWithAccessControlSuccess.html"); | |
| 561 char redirect[] = | |
| 562 "http://www.other.com/" | |
| 563 "RedirectCrossOriginWithAccessControlSuccess.html"; // Cross-origin | |
| 564 KURL redirectURL = toKURL(redirect); | |
| 565 | |
| 566 WebURLRequest request; | |
| 567 request.setURL(url); | |
| 568 // Add a CORS simple header. | |
| 569 request.setHTTPHeaderField("accept", "application/json"); | |
| 570 | |
| 571 // Create a redirect response that allows the redirect to pass the access | |
| 572 // control checks. | |
| 573 m_expectedRedirectResponse = WebURLResponse(); | |
| 574 m_expectedRedirectResponse.setMIMEType("text/html"); | |
| 575 m_expectedRedirectResponse.setHTTPStatusCode(301); | |
| 576 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); | |
| 577 m_expectedRedirectResponse.addHTTPHeaderField("access-control-allow-origin", | |
| 578 "*"); | |
| 579 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 580 url, m_expectedRedirectResponse, m_frameFilePath); | |
| 581 | |
| 582 m_expectedNewRequest = WebURLRequest(); | |
| 583 m_expectedNewRequest.setURL(redirectURL); | |
| 584 m_expectedNewRequest.setHTTPHeaderField("accept", "application/json"); | |
| 585 | |
| 586 m_expectedResponse = WebURLResponse(); | |
| 587 m_expectedResponse.setMIMEType("text/html"); | |
| 588 m_expectedResponse.setHTTPStatusCode(200); | |
| 589 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); | |
| 590 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 591 redirectURL, m_expectedResponse, m_frameFilePath); | |
| 592 | |
| 593 WebURLLoaderOptions options; | |
| 594 options.crossOriginRequestPolicy = | |
| 595 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
| 596 m_expectedLoader = createAssociatedURLLoader(options); | |
| 597 EXPECT_TRUE(m_expectedLoader); | |
| 598 m_expectedLoader->loadAsynchronously(request, this); | |
| 599 serveRequests(); | |
| 600 // We should not receive a notification for the redirect. | |
| 601 EXPECT_FALSE(m_willFollowRedirect); | |
| 602 EXPECT_TRUE(m_didReceiveResponse); | |
| 603 EXPECT_TRUE(m_didReceiveData); | |
| 604 EXPECT_TRUE(m_didFinishLoading); | |
| 605 } | |
| 606 | |
| 607 // Test that untrusted loads can't use a forbidden method. | |
| 608 TEST_F(AssociatedURLLoaderTest, UntrustedCheckMethods) { | |
| 609 // Check non-token method fails. | |
| 610 CheckMethodFails("GET()"); | |
| 611 CheckMethodFails("POST\x0d\x0ax-csrf-token:\x20test1234"); | |
| 612 | |
| 613 // Forbidden methods should fail regardless of casing. | |
| 614 CheckMethodFails("CoNneCt"); | |
| 615 CheckMethodFails("TrAcK"); | |
| 616 CheckMethodFails("TrAcE"); | |
| 617 } | |
| 618 | |
| 619 // This test is flaky on Windows and Android. See <http://crbug.com/471645>. | |
| 620 #if OS(WIN) || OS(ANDROID) | |
| 621 #define MAYBE_UntrustedCheckHeaders DISABLED_UntrustedCheckHeaders | |
| 622 #else | |
| 623 #define MAYBE_UntrustedCheckHeaders UntrustedCheckHeaders | |
| 624 #endif | |
| 625 | |
| 626 // Test that untrusted loads can't use a forbidden header field. | |
| 627 TEST_F(AssociatedURLLoaderTest, MAYBE_UntrustedCheckHeaders) { | |
| 628 // Check non-token header fails. | |
| 629 CheckHeaderFails("foo()"); | |
| 630 | |
| 631 // Check forbidden headers fail. | |
| 632 CheckHeaderFails("accept-charset"); | |
| 633 CheckHeaderFails("accept-encoding"); | |
| 634 CheckHeaderFails("connection"); | |
| 635 CheckHeaderFails("content-length"); | |
| 636 CheckHeaderFails("cookie"); | |
| 637 CheckHeaderFails("cookie2"); | |
| 638 CheckHeaderFails("date"); | |
| 639 CheckHeaderFails("dnt"); | |
| 640 CheckHeaderFails("expect"); | |
| 641 CheckHeaderFails("host"); | |
| 642 CheckHeaderFails("keep-alive"); | |
| 643 CheckHeaderFails("origin"); | |
| 644 CheckHeaderFails("referer", "http://example.com/"); | |
| 645 CheckHeaderFails("te"); | |
| 646 CheckHeaderFails("trailer"); | |
| 647 CheckHeaderFails("transfer-encoding"); | |
| 648 CheckHeaderFails("upgrade"); | |
| 649 CheckHeaderFails("user-agent"); | |
| 650 CheckHeaderFails("via"); | |
| 651 | |
| 652 CheckHeaderFails("proxy-"); | |
| 653 CheckHeaderFails("proxy-foo"); | |
| 654 CheckHeaderFails("sec-"); | |
| 655 CheckHeaderFails("sec-foo"); | |
| 656 | |
| 657 // Check that validation is case-insensitive. | |
| 658 CheckHeaderFails("AcCePt-ChArSeT"); | |
| 659 CheckHeaderFails("ProXy-FoO"); | |
| 660 | |
| 661 // Check invalid header values. | |
| 662 CheckHeaderFails("foo", "bar\x0d\x0ax-csrf-token:\x20test1234"); | |
| 663 } | |
| 664 | |
| 665 // Test that the loader filters response headers according to the CORS standard. | |
| 666 TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderWhitelisting) { | |
| 667 // Test that whitelisted headers are returned without exposing them. | |
| 668 EXPECT_TRUE(CheckAccessControlHeaders("cache-control", false)); | |
| 669 EXPECT_TRUE(CheckAccessControlHeaders("content-language", false)); | |
| 670 EXPECT_TRUE(CheckAccessControlHeaders("content-type", false)); | |
| 671 EXPECT_TRUE(CheckAccessControlHeaders("expires", false)); | |
| 672 EXPECT_TRUE(CheckAccessControlHeaders("last-modified", false)); | |
| 673 EXPECT_TRUE(CheckAccessControlHeaders("pragma", false)); | |
| 674 | |
| 675 // Test that non-whitelisted headers aren't returned. | |
| 676 EXPECT_FALSE(CheckAccessControlHeaders("non-whitelisted", false)); | |
| 677 | |
| 678 // Test that Set-Cookie headers aren't returned. | |
| 679 EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", false)); | |
| 680 EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie2", false)); | |
| 681 | |
| 682 // Test that exposed headers that aren't whitelisted are returned. | |
| 683 EXPECT_TRUE(CheckAccessControlHeaders("non-whitelisted", true)); | |
| 684 | |
| 685 // Test that Set-Cookie headers aren't returned, even if exposed. | |
| 686 EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", true)); | |
| 687 } | |
| 688 | |
| 689 // Test that the loader can allow non-whitelisted response headers for trusted | |
| 690 // CORS loads. | |
| 691 TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderAllowResponseHeaders) { | |
| 692 WebURLRequest request; | |
| 693 KURL url = | |
| 694 toKURL("http://www.other.com/CrossOriginHeaderAllowResponseHeaders.html"); | |
| 695 request.setURL(url); | |
| 696 | |
| 697 WebString headerNameString(WebString::fromUTF8("non-whitelisted")); | |
| 698 m_expectedResponse = WebURLResponse(); | |
| 699 m_expectedResponse.setMIMEType("text/html"); | |
| 700 m_expectedResponse.setHTTPStatusCode(200); | |
| 701 m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*"); | |
| 702 m_expectedResponse.addHTTPHeaderField(headerNameString, "foo"); | |
| 703 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
| 704 url, m_expectedResponse, m_frameFilePath); | |
| 705 | |
| 706 WebURLLoaderOptions options; | |
| 707 options.exposeAllResponseHeaders = | |
| 708 true; // This turns off response whitelisting. | |
| 709 options.crossOriginRequestPolicy = | |
| 710 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
| 711 m_expectedLoader = createAssociatedURLLoader(options); | |
| 712 EXPECT_TRUE(m_expectedLoader); | |
| 713 m_expectedLoader->loadAsynchronously(request, this); | |
| 714 serveRequests(); | |
| 715 EXPECT_TRUE(m_didReceiveResponse); | |
| 716 EXPECT_TRUE(m_didReceiveData); | |
| 717 EXPECT_TRUE(m_didFinishLoading); | |
| 718 | |
| 719 EXPECT_FALSE(m_actualResponse.httpHeaderField(headerNameString).isEmpty()); | |
| 720 } | |
| 721 | |
| 722 } // namespace blink | |
| OLD | NEW |