| 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 | 
|---|