Changeset 112217 in webkit


Ignore:
Timestamp:
Mar 27, 2012 12:38:47 AM (12 years ago)
Author:
bbudge@chromium.org
Message:

cross-origin XMLHttpRequest doesn't work with redirect
https://bugs.webkit.org/show_bug.cgi?id=57600

Reviewed by Adam Barth.

Source/WebCore:

Changes DocumentThreadableLoader to follow the CORS redirect steps when
asynchronously loading a cross origin request with access control. Synchronous
loads should not be affected. Also adds methods to ResourceRequestBase to
clear special request headers that aren't allowed when using access control.
Follows the CORS spec as described in the Latest Editor Draft at:
http://www.w3.org/TR/cors/

Test: http/tests/xmlhttprequest/access-control-and-redirects-async.html

  • loader/DocumentThreadableLoader.cpp:
  • loader/DocumentThreadableLoader.h:
  • platform/network/ResourceRequestBase.cpp:
  • platform/network/ResourceRequestBase.h:

LayoutTests:

Adds tests to verify that an asynchronous XHR load that receives a redirect
response follows the CORS redirect steps.
Follows the CORS spec as described in the Latest Editor Draft at:
http://www.w3.org/TR/cors/

  • http/tests/security/resources/cors-redirect.php: Removed.
  • http/tests/security/xhr-cors-redirect.html: Removed.
  • http/tests/xmlhttprequest/access-control-and-redirects-async-expected.txt: Added.
  • http/tests/xmlhttprequest/access-control-and-redirects-async.html: Added.
  • http/tests/xmlhttprequest/resources/redirect-cors.php: Added.
Location:
trunk
Files:
3 added
2 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r112216 r112217  
     12012-03-27  Bill Budge  <bbudge@chromium.org>
     2
     3        cross-origin XMLHttpRequest doesn't work with redirect
     4        https://bugs.webkit.org/show_bug.cgi?id=57600
     5
     6        Reviewed by Adam Barth.
     7
     8        Adds tests to verify that an asynchronous XHR load that receives a redirect
     9        response follows the CORS redirect steps.
     10        Follows the CORS spec as described in the Latest Editor Draft at:
     11        http://www.w3.org/TR/cors/
     12
     13        * http/tests/security/resources/cors-redirect.php: Removed.
     14        * http/tests/security/xhr-cors-redirect.html: Removed.
     15        * http/tests/xmlhttprequest/access-control-and-redirects-async-expected.txt: Added.
     16        * http/tests/xmlhttprequest/access-control-and-redirects-async.html: Added.
     17        * http/tests/xmlhttprequest/resources/redirect-cors.php: Added.
     18
    1192012-03-27  Philippe Normand  <pnormand@igalia.com>
    220
  • trunk/Source/WebCore/ChangeLog

    r112215 r112217  
     12012-03-27  Bill Budge  <bbudge@chromium.org>
     2
     3        cross-origin XMLHttpRequest doesn't work with redirect
     4        https://bugs.webkit.org/show_bug.cgi?id=57600
     5
     6        Reviewed by Adam Barth.
     7
     8        Changes DocumentThreadableLoader to follow the CORS redirect steps when
     9        asynchronously loading a cross origin request with access control. Synchronous
     10        loads should not be affected. Also adds methods to ResourceRequestBase to
     11        clear special request headers that aren't allowed when using access control.
     12        Follows the CORS spec as described in the Latest Editor Draft at:
     13        http://www.w3.org/TR/cors/
     14
     15        Test: http/tests/xmlhttprequest/access-control-and-redirects-async.html
     16
     17        * loader/DocumentThreadableLoader.cpp:
     18        * loader/DocumentThreadableLoader.h:
     19        * platform/network/ResourceRequestBase.cpp:
     20        * platform/network/ResourceRequestBase.h:
     21
    1222012-03-27  Adam Barth  <abarth@webkit.org>
    223
  • trunk/Source/WebCore/loader/DocumentThreadableLoader.cpp

    r106057 r112217  
    11/*
    2  * Copyright (C) 2011 Google Inc. All rights reserved.
     2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    7575    , m_options(options)
    7676    , m_sameOriginRequest(securityOrigin()->canRequest(request.url()))
     77    , m_simpleRequest(true)
    7778    , m_async(blockingBehavior == LoadAsynchronously)
    7879#if ENABLE(INSPECTOR)
     
    8586    ASSERT(m_async || request.httpReferrer().isEmpty());
    8687
     88    makeRequest(request);
     89}
     90
     91void DocumentThreadableLoader::makeRequest(const ResourceRequest& request)
     92{
    8793    if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossOriginRequests) {
    8894        loadRequest(request, DoSecurityCheck);
     
    94100        return;
    95101    }
    96    
     102
    97103    ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
    98104
     
    103109        makeSimpleCrossOriginAccessRequest(*crossOriginRequest);
    104110    else {
     111        m_simpleRequest = false;
    105112        m_actualRequest = crossOriginRequest.release();
    106113
     
    168175    ASSERT_UNUSED(resource, resource == m_resource);
    169176
    170     if (!isAllowedRedirect(request.url())) {
    171         RefPtr<DocumentThreadableLoader> protect(this);
     177    RefPtr<DocumentThreadableLoader> protect(this);
     178    bool allowRedirect = false;
     179    if (m_options.crossOriginRequestPolicy == UseAccessControl) {
     180        // When using access control, only simple cross origin requests are allowed to redirect. The new request URL must have a supported
     181        // scheme and not contain the userinfo production. In addition, the redirect response must pass the access control check.
     182        if (m_simpleRequest) {
     183            String accessControlErrorDescription;
     184            allowRedirect = SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protocol())
     185                            && request.url().user().isEmpty()
     186                            && request.url().pass().isEmpty()
     187                            && passesAccessControlCheck(redirectResponse, m_options.allowCredentials, securityOrigin(), accessControlErrorDescription);
     188        }
     189    } else
     190        allowRedirect = isAllowedRedirect(request.url());
     191
     192    if (allowRedirect) {
     193        if (m_options.crossOriginRequestPolicy == UseAccessControl) {
     194            if (m_resource)
     195                clearResource();
     196
     197            RefPtr<SecurityOrigin> originalOrigin = SecurityOrigin::createFromString(redirectResponse.url());
     198            RefPtr<SecurityOrigin> requestOrigin = SecurityOrigin::createFromString(request.url());
     199            // If the request URL origin is not same origin with the original URL origin, set source origin to a globally unique identifier.
     200            if (!originalOrigin->isSameSchemeHostPort(requestOrigin.get()))
     201                m_options.securityOrigin = SecurityOrigin::createUnique();
     202            m_sameOriginRequest = securityOrigin()->canRequest(request.url());
     203
     204            // Remove any headers that may have been added by the network layer that cause access control to fail.
     205            request.clearHTTPContentType();
     206            request.clearHTTPReferrer();
     207            request.clearHTTPOrigin();
     208            request.clearHTTPUserAgent();
     209            request.clearHTTPAccept();
     210            makeRequest(request);
     211        } else {
     212            // If not using access control, allow clients to audit the redirect.
     213            if (m_client->isDocumentThreadableLoaderClient())
     214                static_cast<DocumentThreadableLoaderClient*>(m_client)->willSendRequest(request, redirectResponse);
     215        }
     216    } else {
    172217        m_client->didFailRedirectCheck();
    173218        request = ResourceRequest();
    174     } else {
    175         if (m_client->isDocumentThreadableLoaderClient())
    176             static_cast<DocumentThreadableLoaderClient*>(m_client)->willSendRequest(request, redirectResponse);
    177219    }
    178220}
     
    378420        return true;
    379421
    380     // FIXME: We need to implement access control for each redirect. This will require some refactoring though, because the code
    381     // that processes redirects doesn't know about access control and expects a synchronous answer from its client about whether
    382     // a redirect should proceed.
    383422    return m_sameOriginRequest && securityOrigin()->canRequest(url);
    384423}
  • trunk/Source/WebCore/loader/DocumentThreadableLoader.h

    r98380 r112217  
    11/*
    2  * Copyright (C) 2009 Google Inc. All rights reserved.
     2 * Copyright (C) 2009, 2012 Google Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    9090        void didFinishLoading(unsigned long identifier, double finishTime);
    9191        void didFail(const ResourceError&);
     92        void makeRequest(const ResourceRequest&);
    9293        void makeSimpleCrossOriginAccessRequest(const ResourceRequest& request);
    9394        void makeCrossOriginAccessRequestWithPreflight(const ResourceRequest& request);
     
    105106        ThreadableLoaderOptions m_options;
    106107        bool m_sameOriginRequest;
     108        bool m_simpleRequest;
    107109        bool m_async;
    108110        OwnPtr<ResourceRequest> m_actualRequest;  // non-null during Access Control preflight checks
  • trunk/Source/WebCore/platform/network/ResourceRequestBase.cpp

    r109670 r112217  
    11/*
    22 * Copyright (C) 2003, 2006 Apple Computer, Inc.  All rights reserved.
    3  * Copyright (C) 2009 Google Inc. All rights reserved.
     3 * Copyright (C) 2009, 2012 Google Inc. All rights reserved.
    44 *
    55 * Redistribution and use in source and binary forms, with or without
     
    252252}
    253253
     254void ResourceRequestBase::clearHTTPContentType()
     255{
     256    updateResourceRequest();
     257
     258    m_httpHeaderFields.remove("Content-Type");
     259
     260    if (url().protocolIsInHTTPFamily())
     261        m_platformRequestUpdated = false;
     262}
     263
    254264void ResourceRequestBase::clearHTTPReferrer()
    255265{
     
    267277
    268278    m_httpHeaderFields.remove("Origin");
     279
     280    if (url().protocolIsInHTTPFamily())
     281        m_platformRequestUpdated = false;
     282}
     283
     284void ResourceRequestBase::clearHTTPUserAgent()
     285{
     286    updateResourceRequest();
     287
     288    m_httpHeaderFields.remove("User-Agent");
     289
     290    if (url().protocolIsInHTTPFamily())
     291        m_platformRequestUpdated = false;
     292}
     293
     294void ResourceRequestBase::clearHTTPAccept()
     295{
     296    updateResourceRequest();
     297
     298    m_httpHeaderFields.remove("Accept");
    269299
    270300    if (url().protocolIsInHTTPFamily())
  • trunk/Source/WebCore/platform/network/ResourceRequestBase.h

    r104723 r112217  
    22 * Copyright (C) 2003, 2006 Apple Computer, Inc.  All rights reserved.
    33 * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
    4  * Copyright (C) 2009 Google Inc. All rights reserved.
     4 * Copyright (C) 2009, 2012 Google Inc. All rights reserved.
    55 *
    66 * Redistribution and use in source and binary forms, with or without
     
    8989        String httpContentType() const { return httpHeaderField("Content-Type");  }
    9090        void setHTTPContentType(const String& httpContentType) { setHTTPHeaderField("Content-Type", httpContentType); }
    91        
     91        void clearHTTPContentType();
     92
    9293        String httpReferrer() const { return httpHeaderField("Referer"); }
    9394        void setHTTPReferrer(const String& httpReferrer) { setHTTPHeaderField("Referer", httpReferrer); }
     
    100101        String httpUserAgent() const { return httpHeaderField("User-Agent"); }
    101102        void setHTTPUserAgent(const String& httpUserAgent) { setHTTPHeaderField("User-Agent", httpUserAgent); }
     103        void clearHTTPUserAgent();
    102104
    103105        String httpAccept() const { return httpHeaderField("Accept"); }
    104106        void setHTTPAccept(const String& httpAccept) { setHTTPHeaderField("Accept", httpAccept); }
     107        void clearHTTPAccept();
    105108
    106109        void setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2 = String(), const String& encoding3 = String());
Note: See TracChangeset for help on using the changeset viewer.