Changeset 105134 in webkit


Ignore:
Timestamp:
Jan 17, 2012 2:26:31 AM (12 years ago)
Author:
bbudge@chromium.org
Message:

AssociatedURLLoader adds support for the HTTP response header Access-Control-Expose-Header.
https://bugs.webkit.org/show_bug.cgi?id=76419

Reviewed by Adam Barth.

  • src/AssociatedURLLoader.cpp:

(WebKit::AssociatedURLLoader::ClientAdapter::didReceiveResponse):

  • tests/AssociatedURLLoaderTest.cpp:

(WebKit::AssociatedURLLoaderTest::CheckAccessControlHeaders):
(WebKit::TEST_F):

Location:
trunk/Source/WebKit/chromium
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/chromium/ChangeLog

    r105087 r105134  
     12012-01-17  Bill Budge  <bbudge@chromium.org>
     2
     3        AssociatedURLLoader adds support for the HTTP response header Access-Control-Expose-Header.
     4        https://bugs.webkit.org/show_bug.cgi?id=76419
     5
     6        Reviewed by Adam Barth.
     7
     8        * src/AssociatedURLLoader.cpp:
     9        (WebKit::AssociatedURLLoader::ClientAdapter::didReceiveResponse):
     10        * tests/AssociatedURLLoaderTest.cpp:
     11        (WebKit::AssociatedURLLoaderTest::CheckAccessControlHeaders):
     12        (WebKit::TEST_F):
     13
    1142012-01-16  Bill Budge  <bbudge@chromium.org>
    215
  • trunk/Source/WebKit/chromium/src/AssociatedURLLoader.cpp

    r105087 r105134  
    11/*
    2  * Copyright (C) 2010, 2011 Google Inc. All rights reserved.
     2 * Copyright (C) 2010, 2011, 2012 Google Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    5151#include "platform/WebURLLoaderClient.h"
    5252#include "platform/WebURLRequest.h"
    53 #include <wtf/Vector.h>
     53#include <wtf/HashSet.h>
    5454#include <wtf/text/WTFString.h>
    5555
     
    7373};
    7474
     75typedef HashSet<String, CaseFoldingHash> HTTPHeaderSet;
     76
    7577void HTTPRequestHeaderValidator::visitHeader(const WebString& name, const WebString& value)
    7678{
     
    8486
    8587    void visitHeader(const WebString& name, const WebString& value);
    86     const Vector<WebString>& disallowedHeaders() const { return m_disallowedHeaders; }
     88    const HTTPHeaderSet& blockedHeaders();
    8789
    8890private:
    89     Vector<WebString> m_disallowedHeaders;
     91    HTTPHeaderSet m_exposedHeaders;
     92    HTTPHeaderSet m_blockedHeaders;
    9093    bool m_usingAccessControl;
    9194};
     
    9497{
    9598    String headerName(name);
    96     // Hide non-whitelisted headers for CORS requests.
    97     // Hide Set-Cookie headers for all requests.
    98     if ((m_usingAccessControl && !isOnAccessControlResponseHeaderWhitelist(headerName))
    99          || (equalIgnoringCase(headerName, "set-cookie") || equalIgnoringCase(headerName, "set-cookie2")))
    100         m_disallowedHeaders.append(name);
     99    if (m_usingAccessControl) {
     100        if (equalIgnoringCase(headerName, "access-control-expose-header"))
     101            parseAccessControlExposeHeadersAllowList(value, m_exposedHeaders);
     102        else if (!isOnAccessControlResponseHeaderWhitelist(headerName))
     103            m_blockedHeaders.add(name);
     104    }
     105}
     106
     107const HTTPHeaderSet& HTTPResponseHeaderValidator::blockedHeaders()
     108{
     109    // Remove exposed headers from the blocked set.
     110    if (!m_exposedHeaders.isEmpty()) {
     111        // Don't allow Set-Cookie headers to be exposed.
     112        m_exposedHeaders.remove("set-cookie");
     113        m_exposedHeaders.remove("set-cookie2");
     114        // Block Access-Control-Expose-Header itself. It could be exposed later.
     115        m_blockedHeaders.add("access-control-expose-header");
     116        HTTPHeaderSet::const_iterator end = m_exposedHeaders.end();
     117        for (HTTPHeaderSet::const_iterator it = m_exposedHeaders.begin(); it != end; ++it)
     118            m_blockedHeaders.remove(*it);
     119    }
     120
     121    return m_blockedHeaders;
    101122}
    102123
     
    188209    HTTPResponseHeaderValidator validator(m_options.crossOriginRequestPolicy == WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl);
    189210    validatedResponse.visitHTTPHeaderFields(&validator);
    190     // If there are disallowed headers, copy the response so we can remove them.
    191     const Vector<WebString>& disallowedHeaders = validator.disallowedHeaders();
    192     if (!disallowedHeaders.isEmpty()) {
     211    // If there are blocked headers, copy the response so we can remove them.
     212    const HTTPHeaderSet& blockedHeaders = validator.blockedHeaders();
     213    if (!blockedHeaders.isEmpty()) {
    193214        validatedResponse = WebURLResponse(validatedResponse);
    194         for (size_t i = 0; i < disallowedHeaders.size(); ++i)
    195             validatedResponse.clearHTTPHeaderField(disallowedHeaders[i]);
     215        HTTPHeaderSet::const_iterator end = blockedHeaders.end();
     216        for (HTTPHeaderSet::const_iterator it = blockedHeaders.begin(); it != end; ++it)
     217            validatedResponse.clearHTTPHeaderField(*it);
    196218    }
    197219    m_client->didReceiveResponse(m_loader, validatedResponse);
  • trunk/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp

    r105087 r105134  
    4141#include "platform/WebURLRequest.h"
    4242#include "platform/WebURLResponse.h"
     43#include <wtf/text/WTFString.h>
    4344
    4445#include <googleurl/src/gurl.h>
     
    220221        EXPECT_TRUE(m_didFail);
    221222        EXPECT_FALSE(m_didReceiveResponse);
     223    }
     224
     225    bool CheckAccessControlHeaders(const char* headerName, bool exposed)
     226    {
     227        std::string id("http://www.other.com/CheckAccessControlExposeHeaders_");
     228        id.append(headerName);
     229        if (exposed)
     230            id.append("-Exposed");
     231        id.append(".html");
     232
     233        GURL url = GURL(id);
     234        WebURLRequest request;
     235        request.initialize();
     236        request.setURL(url);
     237
     238        WebString headerNameString(WebString::fromUTF8(headerName));
     239        m_expectedResponse = WebURLResponse();
     240        m_expectedResponse.initialize();
     241        m_expectedResponse.setMIMEType("text/html");
     242        m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*");
     243        if (exposed)
     244            m_expectedResponse.addHTTPHeaderField("access-control-expose-header", headerNameString);
     245        m_expectedResponse.addHTTPHeaderField(headerNameString, "foo");
     246        webkit_support::RegisterMockedURL(url, m_expectedResponse, m_frameFilePath);
     247
     248        WebURLLoaderOptions options;
     249        options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
     250        m_expectedLoader = createAssociatedURLLoader(options);
     251        EXPECT_TRUE(m_expectedLoader);
     252        m_expectedLoader->loadAsynchronously(request, this);
     253        serveRequests();
     254        EXPECT_TRUE(m_didReceiveResponse);
     255        EXPECT_TRUE(m_didReceiveData);
     256        EXPECT_TRUE(m_didFinishLoading);
     257
     258        return !m_actualResponse.httpHeaderField(headerNameString).isEmpty();
    222259    }
    223260
     
    490527}
    491528
    492 // Test that a CORS load only returns whitelisted headers.
     529// Test that the loader filters response headers according to the CORS standard.
    493530TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderWhitelisting)
    494531{
    495     // This is cross-origin since the frame was loaded from www.test.com.
    496     GURL url = GURL("http://www.other.com/CrossOriginHeaderWhitelisting.html");
    497     WebURLRequest request;
    498     request.initialize();
    499     request.setURL(url);
    500 
    501     m_expectedResponse = WebURLResponse();
    502     m_expectedResponse.initialize();
    503     m_expectedResponse.setMIMEType("text/html");
    504     m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*");
    505     // These headers are whitelisted and should be in the response.
    506     m_expectedResponse.addHTTPHeaderField("cache-control", "foo");
    507     m_expectedResponse.addHTTPHeaderField("content-language", "foo");
    508     m_expectedResponse.addHTTPHeaderField("content-type", "foo");
    509     m_expectedResponse.addHTTPHeaderField("expires", "foo");
    510     m_expectedResponse.addHTTPHeaderField("last-modified", "foo");
    511     m_expectedResponse.addHTTPHeaderField("pragma", "foo");
    512     // These should never be in the response.
    513     m_expectedResponse.addHTTPHeaderField("Set-Cookie", "foo");
    514     m_expectedResponse.addHTTPHeaderField("Set-Cookie2", "foo");
    515     webkit_support::RegisterMockedURL(url, m_expectedResponse, m_frameFilePath);
    516 
    517     WebURLLoaderOptions options;
    518     options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
    519     m_expectedLoader = createAssociatedURLLoader(options);
    520     EXPECT_TRUE(m_expectedLoader);
    521     m_expectedLoader->loadAsynchronously(request, this);
    522     serveRequests();
    523     EXPECT_TRUE(m_didReceiveResponse);
    524     EXPECT_TRUE(m_didReceiveData);
    525     EXPECT_TRUE(m_didFinishLoading);
    526 
    527     EXPECT_FALSE(m_actualResponse.httpHeaderField("cache-control").isEmpty());
    528     EXPECT_FALSE(m_actualResponse.httpHeaderField("content-language").isEmpty());
    529     EXPECT_FALSE(m_actualResponse.httpHeaderField("content-type").isEmpty());
    530     EXPECT_FALSE(m_actualResponse.httpHeaderField("expires").isEmpty());
    531     EXPECT_FALSE(m_actualResponse.httpHeaderField("last-modified").isEmpty());
    532     EXPECT_FALSE(m_actualResponse.httpHeaderField("pragma").isEmpty());
    533 
    534     EXPECT_TRUE(m_actualResponse.httpHeaderField("Set-Cookie").isEmpty());
    535     EXPECT_TRUE(m_actualResponse.httpHeaderField("Set-Cookie2").isEmpty());
    536 }
    537 
    538 }
     532    // Test that whitelisted headers are returned without exposing them.
     533    EXPECT_TRUE(CheckAccessControlHeaders("cache-control", false));
     534    EXPECT_TRUE(CheckAccessControlHeaders("content-language", false));
     535    EXPECT_TRUE(CheckAccessControlHeaders("content-type", false));
     536    EXPECT_TRUE(CheckAccessControlHeaders("expires", false));
     537    EXPECT_TRUE(CheckAccessControlHeaders("last-modified", false));
     538    EXPECT_TRUE(CheckAccessControlHeaders("pragma", false));
     539
     540    // Test that non-whitelisted headers aren't returned.
     541    EXPECT_FALSE(CheckAccessControlHeaders("non-whitelisted", false));
     542
     543    // Test that Set-Cookie headers aren't returned.
     544    EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", false));
     545    EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie2", false));
     546
     547    // Test that exposed headers that aren't whitelisted are returned.
     548    EXPECT_TRUE(CheckAccessControlHeaders("non-whitelisted", true));
     549
     550    // Test that Set-Cookie headers aren't returned, even if exposed.
     551    EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", true));
     552}
     553
     554}
Note: See TracChangeset for help on using the changeset viewer.