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