Changeset 145973 in webkit


Ignore:
Timestamp:
Mar 15, 2013 6:20:44 PM (11 years ago)
Author:
Nate Chapin
Message:

Merge MainResourceLoader::willSendRequest into DocumentLoader
https://bugs.webkit.org/show_bug.cgi?id=109757

This is one of the steps to merging MainResourceLoader entirely into
DocumentLoader, given the lack of clear division of responsibility
between the two.

Reviewed by Antti Koivisto.

No new tests, refactor only.

  • loader/DocumentLoader.cpp:

(WebCore::DocumentLoader::mainResourceData):
(WebCore::DocumentLoader::isPostOrRedirectAfterPost):
(WebCore::DocumentLoader::willSendRequest):
(WebCore::DocumentLoader::callContinueAfterNavigationPolicy):
(WebCore::DocumentLoader::continueAfterNavigationPolicy):
(WebCore::DocumentLoader::startLoadingMainResource):

  • loader/DocumentLoader.h:
  • loader/MainResourceLoader.cpp:

(WebCore::MainResourceLoader::resourceData):
(WebCore::MainResourceLoader::redirectReceived):
(WebCore::MainResourceLoader::continueAfterContentPolicy):
(WebCore::MainResourceLoader::reportMemoryUsage):
(WebCore::MainResourceLoader::handleSubstituteDataLoadNow):
(WebCore::MainResourceLoader::load):

  • loader/MainResourceLoader.h:

(WebCore::MainResourceLoader::takeIdentifierFromResourceLoader): Temporarily

exposed for moving from a normal load to SubstituteData load on redirect.

Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r145972 r145973  
     12013-03-15  Nate Chapin  <japhet@chromium.org>
     2
     3        Merge MainResourceLoader::willSendRequest into DocumentLoader
     4        https://bugs.webkit.org/show_bug.cgi?id=109757
     5
     6        This is one of the steps to merging MainResourceLoader entirely into
     7        DocumentLoader, given the lack of clear division of responsibility
     8        between the two.
     9
     10        Reviewed by Antti Koivisto.
     11
     12        No new tests, refactor only.
     13
     14        * loader/DocumentLoader.cpp:
     15        (WebCore::DocumentLoader::mainResourceData):
     16        (WebCore::DocumentLoader::isPostOrRedirectAfterPost):
     17        (WebCore::DocumentLoader::willSendRequest):
     18        (WebCore::DocumentLoader::callContinueAfterNavigationPolicy):
     19        (WebCore::DocumentLoader::continueAfterNavigationPolicy):
     20        (WebCore::DocumentLoader::startLoadingMainResource):
     21        * loader/DocumentLoader.h:
     22        * loader/MainResourceLoader.cpp:
     23        (WebCore::MainResourceLoader::resourceData):
     24        (WebCore::MainResourceLoader::redirectReceived):
     25        (WebCore::MainResourceLoader::continueAfterContentPolicy):
     26        (WebCore::MainResourceLoader::reportMemoryUsage):
     27        (WebCore::MainResourceLoader::handleSubstituteDataLoadNow):
     28        (WebCore::MainResourceLoader::load):
     29        * loader/MainResourceLoader.h:
     30        (WebCore::MainResourceLoader::takeIdentifierFromResourceLoader): Temporarily
     31            exposed for moving from a normal load to SubstituteData load on redirect.
     32
    1332013-03-15  Zhenyao Mo  <zmo@google.com>
    234
  • trunk/Source/WebCore/loader/DocumentLoader.cpp

    r145914 r145973  
    4040#include "DocumentWriter.h"
    4141#include "Event.h"
     42#include "FormState.h"
    4243#include "Frame.h"
    4344#include "FrameLoader.h"
    4445#include "FrameLoaderClient.h"
    4546#include "FrameTree.h"
     47#include "HTMLFormElement.h"
    4648#include "HistoryItem.h"
    4749#include "InspectorInstrumentation.h"
     
    140142    if (m_mainResourceData)
    141143        return m_mainResourceData;
     144    if (m_substituteData.isValid())
     145        return ResourceBuffer::create(m_substituteData.content()->data(), m_substituteData.content()->size());
    142146    if (m_mainResourceLoader)
    143147        return m_mainResourceLoader->resourceData();
     
    367371    }
    368372    m_applicationCacheHost->finishedLoadingMainResource();
     373}
     374
     375bool DocumentLoader::isPostOrRedirectAfterPost(const ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
     376{
     377    if (newRequest.httpMethod() == "POST")
     378        return true;
     379
     380    int status = redirectResponse.httpStatusCode();
     381    if (((status >= 301 && status <= 303) || status == 307)
     382        && m_originalRequest.httpMethod() == "POST")
     383        return true;
     384
     385    return false;
     386}
     387
     388void DocumentLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
     389{
     390    // Note that there are no asserts here as there are for the other callbacks. This is due to the
     391    // fact that this "callback" is sent when starting every load, and the state of callback
     392    // deferrals plays less of a part in this function in preventing the bad behavior deferring
     393    // callbacks is meant to prevent.
     394    ASSERT(!newRequest.isNull());
     395
     396    if (!frameLoader()->checkIfFormActionAllowedByCSP(newRequest.url())) {
     397        cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
     398        return;
     399    }
     400
     401    ASSERT(timing()->fetchStart());
     402    if (!redirectResponse.isNull()) {
     403        // If the redirecting url is not allowed to display content from the target origin,
     404        // then block the redirect.
     405        RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url());
     406        if (!redirectingOrigin->canDisplay(newRequest.url())) {
     407            FrameLoader::reportLocalLoadFailed(m_frame, newRequest.url().string());
     408            cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
     409            return;
     410        }
     411        timing()->addRedirect(redirectResponse.url(), newRequest.url());
     412    }
     413
     414    // Update cookie policy base URL as URL changes, except for subframes, which use the
     415    // URL of the main frame which doesn't change when we redirect.
     416    if (frameLoader()->isLoadingMainFrame())
     417        newRequest.setFirstPartyForCookies(newRequest.url());
     418
     419    // If we're fielding a redirect in response to a POST, force a load from origin, since
     420    // this is a common site technique to return to a page viewing some data that the POST
     421    // just modified.
     422    // Also, POST requests always load from origin, but this does not affect subresources.
     423    if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse))
     424        newRequest.setCachePolicy(ReloadIgnoringCacheData);
     425
     426    Frame* top = m_frame->tree()->top();
     427    if (top != m_frame) {
     428        if (!frameLoader()->mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), newRequest.url())) {
     429            cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
     430            return;
     431        }
     432    }
     433
     434    setRequest(newRequest);
     435
     436    if (!redirectResponse.isNull()) {
     437        // We checked application cache for initial URL, now we need to check it for redirected one.
     438        ASSERT(!m_substituteData.isValid());
     439        m_applicationCacheHost->maybeLoadMainResourceForRedirect(newRequest, m_substituteData);
     440        if (m_substituteData.isValid())
     441            m_mainResourceLoader->takeIdentifierFromResourceLoader();
     442    }
     443
     444    // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate
     445    // listener. But there's no way to do that in practice. So instead we cancel later if the
     446    // listener tells us to. In practice that means the navigation policy needs to be decided
     447    // synchronously for these redirect cases.
     448    if (!redirectResponse.isNull())
     449        frameLoader()->policyChecker()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this);
     450}
     451
     452void DocumentLoader::callContinueAfterNavigationPolicy(void* argument, const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
     453{
     454    static_cast<DocumentLoader*>(argument)->continueAfterNavigationPolicy(request, shouldContinue);
     455}
     456
     457void DocumentLoader::continueAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
     458{
     459    if (!shouldContinue)
     460        m_mainResourceLoader->stopLoadingForPolicyChange();
     461    else if (m_substituteData.isValid()) {
     462        // A redirect resulted in loading substitute data.
     463        ASSERT(timing()->redirectCount());
     464
     465        // We need to remove our reference to the CachedResource in favor of a SubstituteData load.
     466        // This will probably trigger the cancellation of the CachedResource's underlying ResourceLoader, though there is a
     467        // small chance that the resource is being loaded by a different Frame, preventing the ResourceLoader from being cancelled.
     468        // If the ResourceLoader is indeed cancelled, it would normally send resource load callbacks.
     469        // However, from an API perspective, this isn't a cancellation. Therefore, sever our relationship with the network load,
     470        // but prevent the ResourceLoader from sending ResourceLoadNotifier callbacks.
     471        RefPtr<ResourceLoader> resourceLoader = m_mainResourceLoader->loader();
     472        ASSERT(resourceLoader->shouldSendResourceLoadCallbacks());
     473        resourceLoader->setSendCallbackPolicy(DoNotSendCallbacks);
     474        m_mainResourceLoader->clearResource();
     475        resourceLoader->setSendCallbackPolicy(SendCallbacks);
     476        m_mainResourceLoader->handleSubstituteDataLoadSoon(request);
     477    }
    369478}
    370479
     
    10311140    // because we pass a wrong loadType (see FIXME in addExtraFieldsToMainResourceRequest()).
    10321141    frameLoader()->addExtraFieldsToMainResourceRequest(m_request);
    1033     m_mainResourceLoader->load(m_request, m_substituteData);
     1142
     1143    ASSERT(timing()->navigationStart());
     1144    ASSERT(!timing()->fetchStart());
     1145    timing()->markFetchStart();
     1146    willSendRequest(m_request, ResourceResponse());
     1147
     1148    // willSendRequest() may lead to our Frame being detached or cancelling the load via nulling the ResourceRequest.
     1149    if (!m_frame || m_request.isNull())
     1150        return;
     1151
     1152    m_applicationCacheHost->maybeLoadMainResource(m_request, m_substituteData);
     1153
     1154    m_mainResourceLoader->load(m_request);
    10341155
    10351156    if (m_request.isNull()) {
  • trunk/Source/WebCore/loader/DocumentLoader.h

    r145914 r145973  
    5959    class CachedResourceLoader;
    6060    class ContentFilter;
     61    class FormState;
    6162    class Frame;
    6263    class FrameLoader;
     
    258259        void checkLoadComplete();
    259260
     261        // FIXME: This should be private once DocumentLoader and MainResourceLoader are merged.
     262        void willSendRequest(ResourceRequest&, const ResourceResponse&);
     263
    260264    protected:
    261265        DocumentLoader(const ResourceRequest&, const SubstituteData&);
     
    277281
    278282        bool isMultipartReplacingLoad() const;
     283        bool isPostOrRedirectAfterPost(const ResourceRequest&, const ResourceResponse&);
     284
     285        static void callContinueAfterNavigationPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue);
     286        void continueAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue);
    279287
    280288        void deliverSubstituteResourcesAfterDelay();
  • trunk/Source/WebCore/loader/MainResourceLoader.cpp

    r145914 r145973  
    4242#include "DocumentLoader.h"
    4343#include "FeatureObserver.h"
    44 #include "FormState.h"
    4544#include "Frame.h"
    4645#include "FrameLoader.h"
     
    160159}
    161160
    162 void MainResourceLoader::callContinueAfterNavigationPolicy(void* argument, const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
    163 {
    164     static_cast<MainResourceLoader*>(argument)->continueAfterNavigationPolicy(request, shouldContinue);
    165 }
    166 
    167 void MainResourceLoader::continueAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
    168 {
    169     if (!shouldContinue)
    170         stopLoadingForPolicyChange();
    171     else if (m_substituteData.isValid()) {
    172         // A redirect resulted in loading substitute data.
    173         ASSERT(documentLoader()->timing()->redirectCount());
    174 
    175         // We need to remove our reference to the CachedResource in favor of a SubstituteData load.
    176         // This will probably trigger the cancellation of the CachedResource's underlying ResourceLoader, though there is a
    177         // small chance that the resource is being loaded by a different Frame, preventing the ResourceLoader from being cancelled.
    178         // If the ResourceLoader is indeed cancelled, it would normally send resource load callbacks.
    179         // However, from an API perspective, this isn't a cancellation. Therefore, sever our relationship with the network load via clearResource(),
    180         // but prevent the ResourceLoader from sending ResourceLoadNotifier callbacks.
    181         RefPtr<ResourceLoader> resourceLoader = loader();
    182         ASSERT(resourceLoader->shouldSendResourceLoadCallbacks());
    183         resourceLoader->setSendCallbackPolicy(DoNotSendCallbacks);
    184         clearResource();
    185         resourceLoader->setSendCallbackPolicy(SendCallbacks);
    186         handleSubstituteDataLoadSoon(request);
    187     }
    188 
    189     deref(); // balances ref in willSendRequest
    190 }
    191 
    192 bool MainResourceLoader::isPostOrRedirectAfterPost(const ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
    193 {
    194     if (newRequest.httpMethod() == "POST")
    195         return true;
    196 
    197     int status = redirectResponse.httpStatusCode();
    198     if (((status >= 301 && status <= 303) || status == 307)
    199         && frameLoader()->initialRequest().httpMethod() == "POST")
    200         return true;
    201    
    202     return false;
    203 }
    204 
    205161PassRefPtr<ResourceBuffer> MainResourceLoader::resourceData()
    206162{
    207     ASSERT(!m_resource || !m_substituteData.isValid());
    208163    if (m_resource)
    209164        return m_resource->resourceBuffer();
    210     if (m_substituteData.isValid())
    211         return ResourceBuffer::create(m_substituteData.content()->data(), m_substituteData.content()->size());
    212165    return 0;
    213166}
     
    216169{
    217170    ASSERT_UNUSED(resource, resource == m_resource);
    218     willSendRequest(request, redirectResponse);
    219 }
    220 
    221 void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
    222 {
    223     // Note that there are no asserts here as there are for the other callbacks. This is due to the
    224     // fact that this "callback" is sent when starting every load, and the state of callback
    225     // deferrals plays less of a part in this function in preventing the bad behavior deferring
    226     // callbacks is meant to prevent.
    227     ASSERT(!newRequest.isNull());
    228 
    229     // The additional processing can do anything including possibly removing the last
    230     // reference to this object; one example of this is 3266216.
    231     RefPtr<MainResourceLoader> protect(this);
    232 
    233     if (!frameLoader()->checkIfFormActionAllowedByCSP(newRequest.url())) {
    234         cancel();
    235         return;
    236     }
    237 
    238     ASSERT(documentLoader()->timing()->fetchStart());
    239     if (!redirectResponse.isNull()) {
    240         // If the redirecting url is not allowed to display content from the target origin,
    241         // then block the redirect.
    242         RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url());
    243         if (!redirectingOrigin->canDisplay(newRequest.url())) {
    244             FrameLoader::reportLocalLoadFailed(m_documentLoader->frame(), newRequest.url().elidedString());
    245             cancel();
    246             return;
    247         }
    248         documentLoader()->timing()->addRedirect(redirectResponse.url(), newRequest.url());
    249     }
    250 
    251     // Update cookie policy base URL as URL changes, except for subframes, which use the
    252     // URL of the main frame which doesn't change when we redirect.
    253     if (frameLoader()->isLoadingMainFrame())
    254         newRequest.setFirstPartyForCookies(newRequest.url());
    255 
    256     // If we're fielding a redirect in response to a POST, force a load from origin, since
    257     // this is a common site technique to return to a page viewing some data that the POST
    258     // just modified.
    259     // Also, POST requests always load from origin, but this does not affect subresources.
    260     if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse))
    261         newRequest.setCachePolicy(ReloadIgnoringCacheData);
    262 
    263     Frame* top = m_documentLoader->frame()->tree()->top();
    264     if (top != m_documentLoader->frame()) {
    265         if (!frameLoader()->mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), newRequest.url())) {
    266             cancel();
    267             return;
    268         }
    269     }
    270 
    271     // Don't set this on the first request. It is set when the main load was started.
    272     m_documentLoader->setRequest(newRequest);
    273 
    274     if (!redirectResponse.isNull()) {
    275         // We checked application cache for initial URL, now we need to check it for redirected one.
    276         ASSERT(!m_substituteData.isValid());
    277         documentLoader()->applicationCacheHost()->maybeLoadMainResourceForRedirect(newRequest, m_substituteData);
    278         if (m_substituteData.isValid())
    279             m_identifierForLoadWithoutResourceLoader = identifier();
    280     }
    281 
    282     // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate
    283     // listener. But there's no way to do that in practice. So instead we cancel later if the
    284     // listener tells us to. In practice that means the navigation policy needs to be decided
    285     // synchronously for these redirect cases.
    286     if (!redirectResponse.isNull()) {
    287         ref(); // balanced by deref in continueAfterNavigationPolicy
    288         frameLoader()->policyChecker()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this);
    289     }
     171    m_documentLoader->willSendRequest(request, redirectResponse);
    290172}
    291173
     
    303185#endif
    304186                                   || equalIgnoringCase("multipart/related", mimeType))
    305             && !m_substituteData.isValid() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol());
     187            && !m_documentLoader->substituteData().isValid() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol());
    306188        if (!frameLoader()->client()->canShowMIMEType(mimeType) || isRemoteWebArchive) {
    307189            frameLoader()->policyChecker()->cannotShowMIMEType(r);
     
    358240    }
    359241
    360     if (!m_documentLoader->isStopping() && m_substituteData.isValid()) {
    361         if (m_substituteData.content()->size())
    362             dataReceived(0, m_substituteData.content()->data(), m_substituteData.content()->size());
     242    if (!m_documentLoader->isStopping() && m_documentLoader->substituteData().isValid()) {
     243        if (m_documentLoader->substituteData().content()->size())
     244            dataReceived(0, m_documentLoader->substituteData().content()->data(), m_documentLoader->substituteData().content()->size());
    363245        if (m_documentLoader->isLoadingMainResource())
    364246            didFinishLoading(0);
     
    512394    info.addMember(m_resource, "resource");
    513395    info.addMember(m_initialRequest, "initialRequest");
    514     info.addMember(m_substituteData, "substituteData");
    515396    info.addMember(m_dataLoadTimer, "dataLoadTimer");
    516397    info.addMember(m_documentLoader, "documentLoader");
     
    521402    RefPtr<MainResourceLoader> protect(this);
    522403
    523     KURL url = m_substituteData.responseURL();
     404    KURL url = m_documentLoader->substituteData().responseURL();
    524405    if (url.isEmpty())
    525406        url = m_initialRequest.url();
     
    529410    m_initialRequest = ResourceRequest();
    530411       
    531     ResourceResponse response(url, m_substituteData.mimeType(), m_substituteData.content()->size(), m_substituteData.textEncoding(), "");
     412    ResourceResponse response(url, m_documentLoader->substituteData().mimeType(), m_documentLoader->substituteData().content()->size(), m_documentLoader->substituteData().textEncoding(), "");
    532413    responseReceived(0, response);
    533414}
     
    553434}
    554435
    555 void MainResourceLoader::load(const ResourceRequest& initialRequest, const SubstituteData& substituteData)
    556 {
    557     // It appears that it is possible for this load to be cancelled and derefenced by the DocumentLoader
    558     // in willSendRequest() if loadNow() is called.
    559     RefPtr<MainResourceLoader> protect(this);
    560 
    561     m_substituteData = substituteData;
    562 
    563     ASSERT(documentLoader()->timing()->navigationStart());
    564     ASSERT(!documentLoader()->timing()->fetchStart());
    565     documentLoader()->timing()->markFetchStart();
     436void MainResourceLoader::load(const ResourceRequest& initialRequest)
     437{
     438    RefPtr<MainResourceLoader> protect(this);
    566439    ResourceRequest request(initialRequest);
    567440
    568     // Send this synthetic delegate callback since clients expect it, and
    569     // we no longer send the callback from within NSURLConnection for
    570     // initial requests.
    571     willSendRequest(request, ResourceResponse());
    572     ASSERT(!deletionHasBegun());
    573 
    574     // willSendRequest() may lead to our DocumentLoader being detached or cancelling the load via nulling the ResourceRequest.
    575     if (!documentLoader()->frame() || request.isNull())
    576         return;
    577 
    578     documentLoader()->applicationCacheHost()->maybeLoadMainResource(request, m_substituteData);
    579 
    580     if (m_substituteData.isValid()) {
     441    if (m_documentLoader->substituteData().isValid()) {
    581442        m_identifierForLoadWithoutResourceLoader = m_documentLoader->frame()->page()->progress()->createUniqueIdentifier();
    582443        frameLoader()->notifier()->assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, documentLoader(), request);
  • trunk/Source/WebCore/loader/MainResourceLoader.h

    r145734 r145973  
    4545namespace WebCore {
    4646
    47 class FormState;
    4847class ResourceRequest;
    4948
     
    5453    virtual ~MainResourceLoader();
    5554
    56     void load(const ResourceRequest&, const SubstituteData&);
     55    void load(const ResourceRequest&);
    5756    void cancel();
    5857    void cancel(const ResourceError&);
     
    7877    void reportMemoryUsage(MemoryObjectInfo*) const;
    7978
     79    void takeIdentifierFromResourceLoader() { m_identifierForLoadWithoutResourceLoader = identifier(); }
     80    void stopLoadingForPolicyChange();
     81    void handleSubstituteDataLoadSoon(const ResourceRequest&);
     82    void clearResource();
     83
    8084private:
    8185    explicit MainResourceLoader(DocumentLoader*);
     
    8690    virtual void notifyFinished(CachedResource*) OVERRIDE;
    8791
    88     void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse);
    8992    void didFinishLoading(double finishTime);
    90     void handleSubstituteDataLoadSoon(const ResourceRequest&);
    9193    void handleSubstituteDataLoadNow(MainResourceLoaderTimer*);
    9294
     
    9597    void receivedError(const ResourceError&);
    9698    ResourceError interruptedForPolicyChangeError() const;
    97     void stopLoadingForPolicyChange();
    98     bool isPostOrRedirectAfterPost(const ResourceRequest& newRequest, const ResourceResponse& redirectResponse);
    99 
    100     static void callContinueAfterNavigationPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue);
    101     void continueAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue);
    10299
    103100    static void callContinueAfterContentPolicy(void*, PolicyAction);
     
    113110
    114111    const ResourceRequest& request() const;
    115     void clearResource();
    116112
    117113    bool defersLoading() const;
     
    120116
    121117    ResourceRequest m_initialRequest;
    122     SubstituteData m_substituteData;
    123118    ResourceResponse m_response;
    124119
Note: See TracChangeset for help on using the changeset viewer.