• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
AssociatedURLLoaderTest()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 
RegisterMockedUrl(const std::string & urlRoot,const WTF::String & filename)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 
SetUp()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 
TearDown()109     void TearDown()
110     {
111         Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
112     }
113 
serveRequests()114     void serveRequests()
115     {
116         Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
117     }
118 
createAssociatedURLLoader(const WebURLLoaderOptions options=WebURLLoaderOptions ())119     PassOwnPtr<WebURLLoader> createAssociatedURLLoader(const WebURLLoaderOptions options = WebURLLoaderOptions())
120     {
121         return adoptPtr(mainFrame()->createAssociatedURLLoader(options));
122     }
123 
124     // WebURLLoaderClient implementation.
willSendRequest(WebURLLoader * loader,WebURLRequest & newRequest,const WebURLResponse & redirectResponse)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 
didSendData(WebURLLoader * loader,unsigned long long bytesSent,unsigned long long totalBytesToBeSent)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 
didReceiveResponse(WebURLLoader * loader,const WebURLResponse & response)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 
didDownloadData(WebURLLoader * loader,int dataLength,int encodedDataLength)152     void didDownloadData(WebURLLoader* loader, int dataLength, int encodedDataLength)
153     {
154         m_didDownloadData = true;
155         EXPECT_EQ(m_expectedLoader, loader);
156     }
157 
didReceiveData(WebURLLoader * loader,const char * data,int dataLength,int encodedDataLength)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 
didReceiveCachedMetadata(WebURLLoader * loader,const char * data,int dataLength)166     void didReceiveCachedMetadata(WebURLLoader* loader, const char* data, int dataLength)
167     {
168         m_didReceiveCachedMetadata = true;
169         EXPECT_EQ(m_expectedLoader, loader);
170     }
171 
didFinishLoading(WebURLLoader * loader,double finishTime,int64_t encodedDataLength)172     void didFinishLoading(WebURLLoader* loader, double finishTime, int64_t encodedDataLength)
173     {
174         m_didFinishLoading = true;
175         EXPECT_EQ(m_expectedLoader, loader);
176     }
177 
didFail(WebURLLoader * loader,const WebURLError & error)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 
CheckMethodFails(const char * unsafeMethod)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 
CheckHeaderFails(const char * headerField)199     void CheckHeaderFails(const char* headerField)
200     {
201         CheckHeaderFails(headerField, "foo");
202     }
203 
CheckHeaderFails(const char * headerField,const char * headerValue)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 
CheckFails(const WebURLRequest & request,WebURLLoaderOptions options=WebURLLoaderOptions ())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 
CheckAccessControlHeaders(const char * headerName,bool exposed)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 
mainFrame() const270     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.
TEST_F(AssociatedURLLoaderTest,SameOriginSuccess)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.
TEST_F(AssociatedURLLoaderTest,SameOriginRestriction)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.
TEST_F(AssociatedURLLoaderTest,CrossOriginSuccess)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.
TEST_F(AssociatedURLLoaderTest,CrossOriginWithAccessControlSuccess)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.
TEST_F(AssociatedURLLoaderTest,CrossOriginWithAccessControlFailure)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.
TEST_F(AssociatedURLLoaderTest,CrossOriginWithAccessControlFailureBadStatusCode)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.
TEST_F(AssociatedURLLoaderTest,RedirectSuccess)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 .
TEST_F(AssociatedURLLoaderTest,DISABLED_RedirectCrossOriginWithAccessControlFailure)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.
TEST_F(AssociatedURLLoaderTest,RedirectCrossOriginWithAccessControlSuccess)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.
TEST_F(AssociatedURLLoaderTest,UntrustedCheckMethods)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.
TEST_F(AssociatedURLLoaderTest,UntrustedCheckHeaders)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.
TEST_F(AssociatedURLLoaderTest,CrossOriginHeaderWhitelisting)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.
TEST_F(AssociatedURLLoaderTest,CrossOriginHeaderAllowResponseHeaders)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