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 "URLTestHelpers.h"
34#include "WebFrame.h"
35#include "WebFrameClient.h"
36#include "WebURLLoaderOptions.h"
37#include "WebView.h"
38#include "public/platform/Platform.h"
39#include "public/platform/WebString.h"
40#include "public/platform/WebThread.h"
41#include "public/platform/WebURL.h"
42#include "public/platform/WebURLLoader.h"
43#include "public/platform/WebURLLoaderClient.h"
44#include "public/platform/WebURLRequest.h"
45#include "public/platform/WebURLResponse.h"
46#include "public/platform/WebUnitTestSupport.h"
47#include "wtf/text/WTFString.h"
48
49#include <gtest/gtest.h>
50
51using namespace WebKit;
52using WebKit::URLTestHelpers::toKURL;
53
54namespace {
55
56class TestWebFrameClient : public WebFrameClient {
57};
58
59class AssociatedURLLoaderTest : public testing::Test,
60                                public WebURLLoaderClient {
61public:
62    AssociatedURLLoaderTest()
63        :  m_willSendRequest(false)
64        ,  m_didSendData(false)
65        ,  m_didReceiveResponse(false)
66        ,  m_didReceiveData(false)
67        ,  m_didReceiveCachedMetadata(false)
68        ,  m_didFinishLoading(false)
69        ,  m_didFail(false)
70        ,  m_runningMessageLoop(false)
71    {
72        // Reuse one of the test files from WebFrameTest.
73        m_baseFilePath = Platform::current()->unitTestSupport()->webKitRootDir();
74        m_baseFilePath.append("/Source/web/tests/data/");
75        m_frameFilePath = m_baseFilePath;
76        m_frameFilePath.append("iframes_test.html");
77    }
78
79    WebCore::KURL RegisterMockedUrl(const std::string& urlRoot, const WTF::String& filename)
80    {
81        WebURLResponse response;
82        response.initialize();
83        response.setMIMEType("text/html");
84        WTF::String localPath = m_baseFilePath;
85        localPath.append(filename);
86        WebCore::KURL url = toKURL(urlRoot + filename.utf8().data());
87        Platform::current()->unitTestSupport()->registerMockedURL(url, response, localPath);
88        return url;
89    }
90
91    void SetUp()
92    {
93        m_webView = WebView::create(0);
94        m_webView->initializeMainFrame(&m_webFrameClient);
95
96        std::string urlRoot = "http://www.test.com/";
97        WebCore::KURL url = RegisterMockedUrl(urlRoot, "iframes_test.html");
98        const char* iframeSupportFiles[] = {
99            "invisible_iframe.html",
100            "visible_iframe.html",
101            "zero_sized_iframe.html",
102        };
103        for (size_t i = 0; i < arraysize(iframeSupportFiles); ++i) {
104            RegisterMockedUrl(urlRoot, iframeSupportFiles[i]);
105        }
106
107        WebURLRequest request;
108        request.initialize();
109        request.setURL(url);
110        m_webView->mainFrame()->loadRequest(request);
111        serveRequests();
112
113        Platform::current()->unitTestSupport()->unregisterMockedURL(url);
114    }
115
116    void TearDown()
117    {
118        Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
119        m_webView->close();
120    }
121
122    void serveRequests()
123    {
124        Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
125    }
126
127    WebURLLoader* createAssociatedURLLoader(const WebURLLoaderOptions options = WebURLLoaderOptions())
128    {
129        return m_webView->mainFrame()->createAssociatedURLLoader(options);
130    }
131
132    // WebURLLoaderClient implementation.
133    void willSendRequest(WebURLLoader* loader, WebURLRequest& newRequest, const WebURLResponse& redirectResponse)
134    {
135        m_willSendRequest = true;
136        EXPECT_EQ(m_expectedLoader, loader);
137        EXPECT_EQ(m_expectedNewRequest.url(), newRequest.url());
138        EXPECT_EQ(m_expectedRedirectResponse.url(), redirectResponse.url());
139        EXPECT_EQ(m_expectedRedirectResponse.httpStatusCode(), redirectResponse.httpStatusCode());
140        EXPECT_EQ(m_expectedRedirectResponse.mimeType(), redirectResponse.mimeType());
141    }
142
143    void didSendData(WebURLLoader* loader, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
144    {
145        m_didSendData = true;
146        EXPECT_EQ(m_expectedLoader, loader);
147    }
148
149    void didReceiveResponse(WebURLLoader* loader, const WebURLResponse& response)
150    {
151        m_didReceiveResponse = true;
152        m_actualResponse = WebURLResponse(response);
153        EXPECT_EQ(m_expectedLoader, loader);
154        EXPECT_EQ(m_expectedResponse.url(), response.url());
155        EXPECT_EQ(m_expectedResponse.httpStatusCode(), response.httpStatusCode());
156    }
157
158    void didDownloadData(WebURLLoader* loader, int dataLength)
159    {
160        m_didDownloadData = true;
161        EXPECT_EQ(m_expectedLoader, loader);
162    }
163
164    void didReceiveData(WebURLLoader* loader, const char* data, int dataLength, int encodedDataLength)
165    {
166        m_didReceiveData = true;
167        EXPECT_EQ(m_expectedLoader, loader);
168        EXPECT_TRUE(data);
169        EXPECT_GT(dataLength, 0);
170    }
171
172    void didReceiveCachedMetadata(WebURLLoader* loader, const char* data, int dataLength)
173    {
174        m_didReceiveCachedMetadata = true;
175        EXPECT_EQ(m_expectedLoader, loader);
176    }
177
178    void didFinishLoading(WebURLLoader* loader, double finishTime)
179    {
180        m_didFinishLoading = true;
181        EXPECT_EQ(m_expectedLoader, loader);
182    }
183
184    void didFail(WebURLLoader* loader, const WebURLError& error)
185    {
186        m_didFail = true;
187        EXPECT_EQ(m_expectedLoader, loader);
188        if (m_runningMessageLoop) {
189            m_runningMessageLoop = false;
190            Platform::current()->currentThread()->exitRunLoop();
191        }
192    }
193
194    void CheckMethodFails(const char* unsafeMethod)
195    {
196        WebURLRequest request;
197        request.initialize();
198        request.setURL(toKURL("http://www.test.com/success.html"));
199        request.setHTTPMethod(WebString::fromUTF8(unsafeMethod));
200        WebURLLoaderOptions options;
201        options.untrustedHTTP = true;
202        CheckFails(request, options);
203    }
204
205    void CheckHeaderFails(const char* headerField)
206    {
207        CheckHeaderFails(headerField, "foo");
208    }
209
210    void CheckHeaderFails(const char* headerField, const char* headerValue)
211    {
212        WebURLRequest request;
213        request.initialize();
214        request.setURL(toKURL("http://www.test.com/success.html"));
215        request.setHTTPHeaderField(WebString::fromUTF8(headerField), WebString::fromUTF8(headerValue));
216        WebURLLoaderOptions options;
217        options.untrustedHTTP = true;
218        CheckFails(request, options);
219    }
220
221    void CheckFails(const WebURLRequest& request, WebURLLoaderOptions options = WebURLLoaderOptions())
222    {
223        m_expectedLoader = createAssociatedURLLoader(options);
224        EXPECT_TRUE(m_expectedLoader);
225        m_didFail = false;
226        m_expectedLoader->loadAsynchronously(request, this);
227        // Failure should not be reported synchronously.
228        EXPECT_FALSE(m_didFail);
229        // Allow the loader to return the error.
230        m_runningMessageLoop = true;
231        Platform::current()->currentThread()->enterRunLoop();
232        EXPECT_TRUE(m_didFail);
233        EXPECT_FALSE(m_didReceiveResponse);
234    }
235
236    bool CheckAccessControlHeaders(const char* headerName, bool exposed)
237    {
238        std::string id("http://www.other.com/CheckAccessControlExposeHeaders_");
239        id.append(headerName);
240        if (exposed)
241            id.append("-Exposed");
242        id.append(".html");
243
244        WebCore::KURL url = toKURL(id);
245        WebURLRequest request;
246        request.initialize();
247        request.setURL(url);
248
249        WebString headerNameString(WebString::fromUTF8(headerName));
250        m_expectedResponse = WebURLResponse();
251        m_expectedResponse.initialize();
252        m_expectedResponse.setMIMEType("text/html");
253        m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*");
254        if (exposed)
255            m_expectedResponse.addHTTPHeaderField("access-control-expose-headers", headerNameString);
256        m_expectedResponse.addHTTPHeaderField(headerNameString, "foo");
257        Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath);
258
259        WebURLLoaderOptions options;
260        options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
261        m_expectedLoader = createAssociatedURLLoader(options);
262        EXPECT_TRUE(m_expectedLoader);
263        m_expectedLoader->loadAsynchronously(request, this);
264        serveRequests();
265        EXPECT_TRUE(m_didReceiveResponse);
266        EXPECT_TRUE(m_didReceiveData);
267        EXPECT_TRUE(m_didFinishLoading);
268
269        return !m_actualResponse.httpHeaderField(headerNameString).isEmpty();
270    }
271
272protected:
273    WTF::String m_baseFilePath;
274    WTF::String m_frameFilePath;
275    TestWebFrameClient m_webFrameClient;
276    WebView* m_webView;
277
278    WebURLLoader* m_expectedLoader;
279    WebURLResponse m_actualResponse;
280    WebURLResponse m_expectedResponse;
281    WebURLRequest m_expectedNewRequest;
282    WebURLResponse m_expectedRedirectResponse;
283    bool m_willSendRequest;
284    bool m_didSendData;
285    bool m_didReceiveResponse;
286    bool m_didDownloadData;
287    bool m_didReceiveData;
288    bool m_didReceiveCachedMetadata;
289    bool m_didFinishLoading;
290    bool m_didFail;
291    bool m_runningMessageLoop;
292};
293
294// Test a successful same-origin URL load.
295TEST_F(AssociatedURLLoaderTest, SameOriginSuccess)
296{
297    WebCore::KURL url = toKURL("http://www.test.com/SameOriginSuccess.html");
298    WebURLRequest request;
299    request.initialize();
300    request.setURL(url);
301
302    m_expectedResponse = WebURLResponse();
303    m_expectedResponse.initialize();
304    m_expectedResponse.setMIMEType("text/html");
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.
317TEST_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.
328TEST_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    Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath);
340
341    WebURLLoaderOptions options;
342    options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
343    m_expectedLoader = createAssociatedURLLoader(options);
344    EXPECT_TRUE(m_expectedLoader);
345    m_expectedLoader->loadAsynchronously(request, this);
346    serveRequests();
347    EXPECT_TRUE(m_didReceiveResponse);
348    EXPECT_TRUE(m_didReceiveData);
349    EXPECT_TRUE(m_didFinishLoading);
350}
351
352// Test a successful cross-origin load using CORS.
353TEST_F(AssociatedURLLoaderTest, CrossOriginWithAccessControlSuccess)
354{
355    // This is cross-origin since the frame was loaded from www.test.com.
356    WebCore::KURL url = toKURL("http://www.other.com/CrossOriginWithAccessControlSuccess.html");
357    WebURLRequest request;
358    request.initialize();
359    request.setURL(url);
360
361    m_expectedResponse = WebURLResponse();
362    m_expectedResponse.initialize();
363    m_expectedResponse.setMIMEType("text/html");
364    m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*");
365    Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath);
366
367    WebURLLoaderOptions options;
368    options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
369    m_expectedLoader = createAssociatedURLLoader(options);
370    EXPECT_TRUE(m_expectedLoader);
371    m_expectedLoader->loadAsynchronously(request, this);
372    serveRequests();
373    EXPECT_TRUE(m_didReceiveResponse);
374    EXPECT_TRUE(m_didReceiveData);
375    EXPECT_TRUE(m_didFinishLoading);
376}
377
378// Test an unsuccessful cross-origin load using CORS.
379TEST_F(AssociatedURLLoaderTest, CrossOriginWithAccessControlFailure)
380{
381    // This is cross-origin since the frame was loaded from www.test.com.
382    WebCore::KURL url = toKURL("http://www.other.com/CrossOriginWithAccessControlFailure.html");
383    WebURLRequest request;
384    request.initialize();
385    request.setURL(url);
386
387    m_expectedResponse = WebURLResponse();
388    m_expectedResponse.initialize();
389    m_expectedResponse.setMIMEType("text/html");
390    m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*");
391    Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath);
392
393    WebURLLoaderOptions options;
394    // Send credentials. This will cause the CORS checks to fail, because credentials can't be
395    // sent to a server which returns the header "access-control-allow-origin" with "*" as its value.
396    options.allowCredentials = true;
397    options.crossOriginRequestPolicy = 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 a same-origin URL redirect and load.
411TEST_F(AssociatedURLLoaderTest, RedirectSuccess)
412{
413    WebCore::KURL url = toKURL("http://www.test.com/RedirectSuccess.html");
414    char redirect[] = "http://www.test.com/RedirectSuccess2.html";  // Same-origin
415    WebCore::KURL redirectURL = toKURL(redirect);
416
417    WebURLRequest request;
418    request.initialize();
419    request.setURL(url);
420
421    m_expectedRedirectResponse = WebURLResponse();
422    m_expectedRedirectResponse.initialize();
423    m_expectedRedirectResponse.setMIMEType("text/html");
424    m_expectedRedirectResponse.setHTTPStatusCode(301);
425    m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect);
426    Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedRedirectResponse, m_frameFilePath);
427
428    m_expectedNewRequest = WebURLRequest();
429    m_expectedNewRequest.initialize();
430    m_expectedNewRequest.setURL(redirectURL);
431
432    m_expectedResponse = WebURLResponse();
433    m_expectedResponse.initialize();
434    m_expectedResponse.setMIMEType("text/html");
435    Platform::current()->unitTestSupport()->registerMockedURL(redirectURL, m_expectedResponse, m_frameFilePath);
436
437    m_expectedLoader = createAssociatedURLLoader();
438    EXPECT_TRUE(m_expectedLoader);
439    m_expectedLoader->loadAsynchronously(request, this);
440    serveRequests();
441    EXPECT_TRUE(m_willSendRequest);
442    EXPECT_TRUE(m_didReceiveResponse);
443    EXPECT_TRUE(m_didReceiveData);
444    EXPECT_TRUE(m_didFinishLoading);
445}
446
447// Test that a cross origin redirect response without CORS headers fails.
448// Disabled, http://crbug.com/240912 .
449TEST_F(AssociatedURLLoaderTest, DISABLED_RedirectCrossOriginWithAccessControlFailure)
450{
451    WebCore::KURL url = toKURL("http://www.test.com/RedirectCrossOriginWithAccessControlFailure.html");
452    char redirect[] = "http://www.other.com/RedirectCrossOriginWithAccessControlFailure.html";  // Cross-origin
453    WebCore::KURL redirectURL = toKURL(redirect);
454
455    WebURLRequest request;
456    request.initialize();
457    request.setURL(url);
458
459    // Create a redirect response without CORS headers.
460    m_expectedRedirectResponse = WebURLResponse();
461    m_expectedRedirectResponse.initialize();
462    m_expectedRedirectResponse.setMIMEType("text/html");
463    m_expectedRedirectResponse.setHTTPStatusCode(301);
464    m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect);
465    Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedRedirectResponse, m_frameFilePath);
466
467    WebURLLoaderOptions options;
468    options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
469    m_expectedLoader = createAssociatedURLLoader(options);
470    EXPECT_TRUE(m_expectedLoader);
471    m_expectedLoader->loadAsynchronously(request, this);
472    serveRequests();
473    // We should not receive a notification for the redirect or any response.
474    EXPECT_FALSE(m_willSendRequest);
475    EXPECT_FALSE(m_didReceiveResponse);
476    EXPECT_FALSE(m_didReceiveData);
477    EXPECT_FALSE(m_didFail);
478}
479
480// Test that a cross origin redirect response with CORS headers that allow the requesting origin succeeds.
481TEST_F(AssociatedURLLoaderTest, RedirectCrossOriginWithAccessControlSuccess)
482{
483    WebCore::KURL url = toKURL("http://www.test.com/RedirectCrossOriginWithAccessControlSuccess.html");
484    char redirect[] = "http://www.other.com/RedirectCrossOriginWithAccessControlSuccess.html";  // Cross-origin
485    WebCore::KURL redirectURL = toKURL(redirect);
486
487    WebURLRequest request;
488    request.initialize();
489    request.setURL(url);
490
491    // Create a redirect response that allows the redirect to pass the access control checks.
492    m_expectedRedirectResponse = WebURLResponse();
493    m_expectedRedirectResponse.initialize();
494    m_expectedRedirectResponse.setMIMEType("text/html");
495    m_expectedRedirectResponse.setHTTPStatusCode(301);
496    m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect);
497    m_expectedRedirectResponse.addHTTPHeaderField("access-control-allow-origin", "*");
498    Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedRedirectResponse, m_frameFilePath);
499
500    m_expectedNewRequest = WebURLRequest();
501    m_expectedNewRequest.initialize();
502    m_expectedNewRequest.setURL(redirectURL);
503
504    m_expectedResponse = WebURLResponse();
505    m_expectedResponse.initialize();
506    m_expectedResponse.setMIMEType("text/html");
507    m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*");
508    Platform::current()->unitTestSupport()->registerMockedURL(redirectURL, m_expectedResponse, m_frameFilePath);
509
510    WebURLLoaderOptions options;
511    options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
512    m_expectedLoader = createAssociatedURLLoader(options);
513    EXPECT_TRUE(m_expectedLoader);
514    m_expectedLoader->loadAsynchronously(request, this);
515    serveRequests();
516    // We should not receive a notification for the redirect.
517    EXPECT_FALSE(m_willSendRequest);
518    EXPECT_TRUE(m_didReceiveResponse);
519    EXPECT_TRUE(m_didReceiveData);
520    EXPECT_TRUE(m_didFinishLoading);
521}
522
523// Test that untrusted loads can't use a forbidden method.
524TEST_F(AssociatedURLLoaderTest, UntrustedCheckMethods)
525{
526    // Check non-token method fails.
527    CheckMethodFails("GET()");
528    CheckMethodFails("POST\x0d\x0ax-csrf-token:\x20test1234");
529
530    // Forbidden methods should fail regardless of casing.
531    CheckMethodFails("CoNneCt");
532    CheckMethodFails("TrAcK");
533    CheckMethodFails("TrAcE");
534}
535
536// Test that untrusted loads can't use a forbidden header field.
537TEST_F(AssociatedURLLoaderTest, UntrustedCheckHeaders)
538{
539    // Check non-token header fails.
540    CheckHeaderFails("foo()");
541
542    // Check forbidden headers fail.
543    CheckHeaderFails("accept-charset");
544    CheckHeaderFails("accept-encoding");
545    CheckHeaderFails("connection");
546    CheckHeaderFails("content-length");
547    CheckHeaderFails("cookie");
548    CheckHeaderFails("cookie2");
549    CheckHeaderFails("content-transfer-encoding");
550    CheckHeaderFails("date");
551    CheckHeaderFails("expect");
552    CheckHeaderFails("host");
553    CheckHeaderFails("keep-alive");
554    CheckHeaderFails("origin");
555    CheckHeaderFails("referer");
556    CheckHeaderFails("te");
557    CheckHeaderFails("trailer");
558    CheckHeaderFails("transfer-encoding");
559    CheckHeaderFails("upgrade");
560    CheckHeaderFails("user-agent");
561    CheckHeaderFails("via");
562
563    CheckHeaderFails("proxy-");
564    CheckHeaderFails("proxy-foo");
565    CheckHeaderFails("sec-");
566    CheckHeaderFails("sec-foo");
567
568    // Check that validation is case-insensitive.
569    CheckHeaderFails("AcCePt-ChArSeT");
570    CheckHeaderFails("ProXy-FoO");
571
572    // Check invalid header values.
573    CheckHeaderFails("foo", "bar\x0d\x0ax-csrf-token:\x20test1234");
574}
575
576// Test that the loader filters response headers according to the CORS standard.
577TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderWhitelisting)
578{
579    // Test that whitelisted headers are returned without exposing them.
580    EXPECT_TRUE(CheckAccessControlHeaders("cache-control", false));
581    EXPECT_TRUE(CheckAccessControlHeaders("content-language", false));
582    EXPECT_TRUE(CheckAccessControlHeaders("content-type", false));
583    EXPECT_TRUE(CheckAccessControlHeaders("expires", false));
584    EXPECT_TRUE(CheckAccessControlHeaders("last-modified", false));
585    EXPECT_TRUE(CheckAccessControlHeaders("pragma", false));
586
587    // Test that non-whitelisted headers aren't returned.
588    EXPECT_FALSE(CheckAccessControlHeaders("non-whitelisted", false));
589
590    // Test that Set-Cookie headers aren't returned.
591    EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", false));
592    EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie2", false));
593
594    // Test that exposed headers that aren't whitelisted are returned.
595    EXPECT_TRUE(CheckAccessControlHeaders("non-whitelisted", true));
596
597    // Test that Set-Cookie headers aren't returned, even if exposed.
598    EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", true));
599}
600
601// Test that the loader can allow non-whitelisted response headers for trusted CORS loads.
602TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderAllowResponseHeaders)
603{
604    WebURLRequest request;
605    request.initialize();
606    WebCore::KURL url = toKURL("http://www.other.com/CrossOriginHeaderAllowResponseHeaders.html");
607    request.setURL(url);
608
609    WebString headerNameString(WebString::fromUTF8("non-whitelisted"));
610    m_expectedResponse = WebURLResponse();
611    m_expectedResponse.initialize();
612    m_expectedResponse.setMIMEType("text/html");
613    m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*");
614    m_expectedResponse.addHTTPHeaderField(headerNameString, "foo");
615    Platform::current()->unitTestSupport()->registerMockedURL(url, m_expectedResponse, m_frameFilePath);
616
617    WebURLLoaderOptions options;
618    options.exposeAllResponseHeaders = true; // This turns off response whitelisting.
619    options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
620    m_expectedLoader = createAssociatedURLLoader(options);
621    EXPECT_TRUE(m_expectedLoader);
622    m_expectedLoader->loadAsynchronously(request, this);
623    serveRequests();
624    EXPECT_TRUE(m_didReceiveResponse);
625    EXPECT_TRUE(m_didReceiveData);
626    EXPECT_TRUE(m_didFinishLoading);
627
628    EXPECT_FALSE(m_actualResponse.httpHeaderField(headerNameString).isEmpty());
629}
630
631}
632