Changeset 52446 in webkit


Ignore:
Timestamp:
Dec 21, 2009 8:55:34 AM (14 years ago)
Author:
Nate Chapin
Message:

2009-12-21 Nate Chapin <Nate Chapin>

Reviewed by Darin Adler.

If an image load is started during an unload or beforeunload event, run it
asynchronously (and allow it to outlive its page) so navigation can continue
while the load completes.

https://bugs.webkit.org/show_bug.cgi?id=30457

Tests: http/tests/navigation/image-load-in-beforeunload-handler.html

http/tests/navigation/image-load-in-unload-handler.html

  • loader/DocumentThreadableLoader.cpp: (WebCore::DocumentThreadableLoader::loadRequest):
  • loader/FrameLoader.cpp: Rename m_unloadEventBeingDispatched to m_isDispatchingUnloadEvent. (WebCore::FrameLoader::FrameLoader): (WebCore::FrameLoader::stopLoading): (WebCore::FrameLoader::loadURL): (WebCore::FrameLoader::loadWithDocumentLoader): (WebCore::FrameLoader::stopAllLoaders): (WebCore::FrameLoader::continueLoadAfterNavigationPolicy): Set m_isDispatchingBeforeUnloadEvent. (WebCore::FrameLoader::pageHidden):
  • loader/FrameLoader.h: (WebCore::FrameLoader::isDispatchingUnloadFamilyEvent): Added.
  • loader/Request.cpp: (WebCore::Request::Request): Add OutlivePagePolicy to constructor parameters
  • loader/Request.h: (WebCore::): Add OutlivePagePolicy enum. (WebCore::Request::shouldOutlivePage): Added. (WebCore::Request::frame): Added.
  • loader/SubresourceLoader.cpp: (WebCore::SubresourceLoader::create): Change one of the security checks to an outlive page check.
  • loader/SubresourceLoader.h:
  • loader/loader.cpp: (WebCore::Loader::load): Add OutlivePagePolicy to Request constructor call,

ensure requests that should outlive page are done asynchronously.

(WebCore::Loader::cancelRequests): Remove ending ASSERT since it will now be hard to predict how

many requests might possibly outlive a cancel in every case.

(WebCore::Loader::Host::servePendingRequests): Use the correct frame in the case of a request outliving its page.
(WebCore::Loader::Host::cancelPendingRequests): Ensure we don't cancel request that should outlive their page.
(WebCore::Loader::Host::cancelRequests): Ensure we don't cancel request that should outlive their page.

Location:
trunk
Files:
5 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r52445 r52446  
     12009-12-21  Nate Chapin  <japhet@chromium.org>
     2
     3        Reviewed by Darin Adler.
     4
     5        Tests for https://bugs.webkit.org/show_bug.cgi?id=30457.
     6
     7        * http/tests/navigation/image-load-in-beforeunload-handler-expected.txt: Added.
     8        * http/tests/navigation/image-load-in-beforeunload-handler.html: Added.
     9        * http/tests/navigation/image-load-in-unload-handler-expected.txt: Added.
     10        * http/tests/navigation/image-load-in-unload-handler.html: Added.
     11        * http/tests/navigation/resources/wait-then-notify-done.html: Added.
     12
    1132009-12-21  Philippe Normand  <pnormand@igalia.com>
    214
  • trunk/WebCore/ChangeLog

    r52441 r52446  
     12009-12-21  Nate Chapin  <japhet@chromium.org>
     2
     3        Reviewed by Darin Adler.
     4
     5        If an image load is started during an unload or beforeunload event, run it
     6        asynchronously (and allow it to outlive its page) so navigation can continue
     7        while the load completes.
     8
     9        https://bugs.webkit.org/show_bug.cgi?id=30457
     10
     11        Tests: http/tests/navigation/image-load-in-beforeunload-handler.html
     12               http/tests/navigation/image-load-in-unload-handler.html
     13
     14        * loader/DocumentThreadableLoader.cpp:
     15        (WebCore::DocumentThreadableLoader::loadRequest):
     16        * loader/FrameLoader.cpp: Rename m_unloadEventBeingDispatched to m_isDispatchingUnloadEvent.
     17        (WebCore::FrameLoader::FrameLoader):
     18        (WebCore::FrameLoader::stopLoading):
     19        (WebCore::FrameLoader::loadURL):
     20        (WebCore::FrameLoader::loadWithDocumentLoader):
     21        (WebCore::FrameLoader::stopAllLoaders):
     22        (WebCore::FrameLoader::continueLoadAfterNavigationPolicy): Set m_isDispatchingBeforeUnloadEvent.
     23        (WebCore::FrameLoader::pageHidden):
     24        * loader/FrameLoader.h:
     25        (WebCore::FrameLoader::isDispatchingUnloadFamilyEvent): Added.
     26        * loader/Request.cpp:
     27        (WebCore::Request::Request): Add OutlivePagePolicy to constructor parameters
     28        * loader/Request.h:
     29        (WebCore::): Add OutlivePagePolicy enum.
     30        (WebCore::Request::shouldOutlivePage): Added.
     31        (WebCore::Request::frame): Added.
     32        * loader/SubresourceLoader.cpp:
     33        (WebCore::SubresourceLoader::create): Change one of the security checks to an outlive page check.
     34        * loader/SubresourceLoader.h:
     35        * loader/loader.cpp:
     36        (WebCore::Loader::load): Add OutlivePagePolicy to Request constructor call,
     37             ensure requests that should outlive page are done asynchronously.
     38        (WebCore::Loader::cancelRequests): Remove ending ASSERT since it will now be hard to predict how
     39             many requests might possibly outlive a cancel in every case.
     40        (WebCore::Loader::Host::servePendingRequests): Use the correct frame in the case of a request outliving its page.
     41        (WebCore::Loader::Host::cancelPendingRequests): Ensure we don't cancel request that should outlive their page.
     42        (WebCore::Loader::Host::cancelRequests): Ensure we don't cancel request that should outlive their page.
     43
    1442009-12-18  Adam Roben  <aroben@apple.com>
    245
  • trunk/WebCore/loader/DocumentThreadableLoader.cpp

    r52177 r52446  
    300300        // Clear the loader so that any callbacks from SubresourceLoader::create will not have the old loader.
    301301        m_loader = 0;
    302         m_loader = SubresourceLoader::create(m_document->frame(), this, request, securityCheck, sendLoadCallbacks, sniffContent);
     302        m_loader = SubresourceLoader::create(m_document->frame(), this, request, securityCheck, DoNotOutlivePage, sendLoadCallbacks, sniffContent);
    303303        return;
    304304    }
  • trunk/WebCore/loader/FrameLoader.cpp

    r52314 r52446  
    181181    , m_didCallImplicitClose(false)
    182182    , m_wasUnloadEventEmitted(false)
    183     , m_unloadEventBeingDispatched(false)
     183    , m_isDispatchingBeforeUnloadEvent(false)
     184    , m_isDispatchingUnloadEvent(false)
    184185    , m_isComplete(false)
    185186    , m_isLoadingMainResource(false)
     
    518519                if (currentFocusedNode)
    519520                    currentFocusedNode->aboutToUnload();
    520                 m_unloadEventBeingDispatched = true;
     521                ASSERT(!m_isDispatchingUnloadEvent);
     522                m_isDispatchingUnloadEvent = true;
    521523                if (m_frame->domWindow()) {
    522524                    if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide)
     
    525527                        m_frame->domWindow()->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), m_frame->domWindow()->document());
    526528                }
    527                 m_unloadEventBeingDispatched = false;
     529                ASSERT(m_isDispatchingUnloadEvent);
     530                m_isDispatchingUnloadEvent = false;
    528531                if (m_frame->document())
    529532                    m_frame->document()->updateStyleIfNeeded();
     
    19091912    }
    19101913
    1911     if (m_unloadEventBeingDispatched)
     1914    if (m_isDispatchingUnloadEvent)
    19121915        return;
    19131916
     
    20352038    ASSERT(m_frame->view());
    20362039
    2037     if (m_unloadEventBeingDispatched)
     2040    if (m_isDispatchingUnloadEvent)
    20382041        return;
    20392042
     
    22772280{
    22782281    ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
    2279     if (m_unloadEventBeingDispatched)
     2282    if (m_isDispatchingUnloadEvent)
    22802283        return;
    22812284
     
    34343437    //    2) User responded Cancel to an alert popped up by the before unload event handler.
    34353438    // The "before unload" event handler runs only for the main frame.
     3439    ASSERT(!m_isDispatchingBeforeUnloadEvent);
     3440    m_isDispatchingBeforeUnloadEvent = true;
    34363441    bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
     3442    ASSERT(m_isDispatchingBeforeUnloadEvent);
     3443    m_isDispatchingBeforeUnloadEvent = false;
    34373444
    34383445    if (!canContinue) {
     
    36283635void FrameLoader::pageHidden()
    36293636{
    3630     m_unloadEventBeingDispatched = true;
     3637    ASSERT(!m_isDispatchingUnloadEvent);
     3638    m_isDispatchingUnloadEvent = true;
    36313639    if (m_frame->domWindow())
    36323640        m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, true), m_frame->document());
    3633     m_unloadEventBeingDispatched = false;
     3641    ASSERT(m_isDispatchingUnloadEvent);
     3642    m_isDispatchingUnloadEvent = false;
    36343643
    36353644    // Send pagehide event for subframes as well
  • trunk/WebCore/loader/FrameLoader.h

    r51644 r52446  
    334334   
    335335    bool suppressOpenerInNewFrame() const { return m_suppressOpenerInNewFrame; }
     336   
     337    bool isDispatchingUnloadFamilyEvent() const { return m_isDispatchingBeforeUnloadEvent || m_isDispatchingUnloadEvent; }
    336338
    337339    static ObjectContentType defaultObjectContentType(const KURL& url, const String& mimeType);
     
    480482    bool m_didCallImplicitClose;
    481483    bool m_wasUnloadEventEmitted;
    482     bool m_unloadEventBeingDispatched;
     484    bool m_isDispatchingBeforeUnloadEvent;
     485    bool m_isDispatchingUnloadEvent;
    483486    bool m_isComplete;
    484487    bool m_isLoadingMainResource;
  • trunk/WebCore/loader/Request.cpp

    r52177 r52446  
    2626
    2727#include "CachedResource.h"
     28#include "DocLoader.h"
     29#include "Frame.h"
    2830
    2931namespace WebCore {
    3032
    31 Request::Request(DocLoader* docLoader, CachedResource* object, bool incremental, SecurityCheckPolicy shouldDoSecurityCheck, bool sendResourceLoadCallbacks)
     33Request::Request(DocLoader* docLoader, CachedResource* object, bool incremental, SecurityCheckPolicy shouldDoSecurityCheck, OutlivePagePolicy outlivePagePolicy, bool sendResourceLoadCallbacks)
    3234    : m_object(object)
    3335    , m_docLoader(docLoader)
     
    3840{
    3941    m_object->setRequest(this);
     42    if (outlivePagePolicy == OutlivePage)
     43        m_frameForRequestThatCanOutlivePage = docLoader->frame();
    4044}
    4145
     
    4448    m_object->setRequest(0);
    4549}
     50   
     51Frame* Request::frame() const
     52{
     53    return m_frameForRequestThatCanOutlivePage ? m_frameForRequestThatCanOutlivePage.get() : m_docLoader->frame();
     54}
    4655
    4756} //namespace WebCore
  • trunk/WebCore/loader/Request.h

    r52177 r52446  
    2525
    2626#include "FrameLoaderTypes.h"
     27#include <wtf/RefPtr.h>
    2728#include <wtf/Vector.h>
    2829
     
    3132    class CachedResource;
    3233    class DocLoader;
     34    class Frame;
     35   
     36    enum OutlivePagePolicy {
     37        DoNotOutlivePage,
     38        OutlivePage
     39    };
    3340
    3441    class Request : public Noncopyable {
    3542    public:
    36         Request(DocLoader*, CachedResource*, bool incremental, SecurityCheckPolicy, bool sendResourceLoadCallbacks);
     43        Request(DocLoader*, CachedResource*, bool incremental, SecurityCheckPolicy, OutlivePagePolicy, bool sendResourceLoadCallbacks);
    3744        ~Request();
    3845       
     
    5057        bool sendResourceLoadCallbacks() const { return m_sendResourceLoadCallbacks; }
    5158       
     59        OutlivePagePolicy canOutlivePage() const { return m_frameForRequestThatCanOutlivePage ? OutlivePage : DoNotOutlivePage; }
     60        Frame* frame() const;
     61       
    5262    private:
    5363        Vector<char> m_buffer;
     
    5868        SecurityCheckPolicy m_shouldDoSecurityCheck;
    5969        bool m_sendResourceLoadCallbacks;
     70        RefPtr<Frame> m_frameForRequestThatCanOutlivePage;
    6071    };
    6172
  • trunk/WebCore/loader/SubresourceLoader.cpp

    r52177 r52446  
    6262}
    6363
    64 PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff)
     64PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request, SecurityCheckPolicy securityCheckPolicy, OutlivePagePolicy outlivePagePolicy, bool sendResourceLoadCallbacks, bool shouldContentSniff)
    6565{
    6666    if (!frame)
     
    6868
    6969    FrameLoader* fl = frame->loader();
    70     if (securityCheck == DoSecurityCheck && (fl->state() == FrameStateProvisional || fl->activeDocumentLoader()->isStopping()))
     70    if (outlivePagePolicy == DoNotOutlivePage && (fl->state() == FrameStateProvisional || fl->activeDocumentLoader()->isStopping()))
    7171        return 0;
    7272
    7373    ResourceRequest newRequest = request;
    7474
    75     if (securityCheck == DoSecurityCheck
     75    if (securityCheckPolicy == DoSecurityCheck
    7676            && SecurityOrigin::restrictAccessToLocal()
    7777            && !SecurityOrigin::canLoad(request.url(), String(), frame->document())) {
  • trunk/WebCore/loader/SubresourceLoader.h

    r52177 r52446  
    3131
    3232#include "FrameLoaderTypes.h"
     33#include "Request.h"
    3334#include "ResourceLoader.h"
    3435 
     
    4041    class SubresourceLoader : public ResourceLoader {
    4142    public:
    42         static PassRefPtr<SubresourceLoader> create(Frame*, SubresourceLoaderClient*, const ResourceRequest&, SecurityCheckPolicy = DoSecurityCheck, bool sendResourceLoadCallbacks = true, bool shouldContentSniff = true);
     43        static PassRefPtr<SubresourceLoader> create(Frame*, SubresourceLoaderClient*, const ResourceRequest&, SecurityCheckPolicy = DoSecurityCheck, OutlivePagePolicy = DoNotOutlivePage, bool sendResourceLoadCallbacks = true, bool shouldContentSniff = true);
    4344
    4445        void clearClient() { m_client = 0; }
  • trunk/WebCore/loader/loader.cpp

    r52177 r52446  
    121121{
    122122    ASSERT(docLoader);
    123     Request* request = new Request(docLoader, resource, incremental, securityCheck, sendResourceLoadCallbacks);
     123   
     124    // If we are loading an image during an unload event, we want to allow the request to outlive the page
     125    // that we are leaving. Some sites (most commonly ad networks) rely on image requests in beforeunload
     126    // or unload event handlers to track time spent on the page. This will allow them to do the tracking
     127    // that they are going to do anyway, but asynchronously so that they don't slow down navigation.
     128    OutlivePagePolicy outlivePagePolicy = resource->isImage() && docLoader && docLoader->frame()
     129        && docLoader->frame()->loader()->isDispatchingUnloadFamilyEvent()
     130        ? OutlivePage : DoNotOutlivePage;
     131   
     132    Request* request = new Request(docLoader, resource, incremental, securityCheck, outlivePagePolicy, sendResourceLoadCallbacks);
    124133
    125134    RefPtr<Host> host;
     
    139148    host->addRequest(request, priority);
    140149    docLoader->incrementRequestCount();
    141 
    142     if (priority > Low || !url.protocolInHTTPFamily() || !hadRequests) {
     150   
     151    // We want to guarantee that requests which outlive the page are run asynchronously, so only
     152    // serve the request immediately if the request doesn't need to outlive the page.
     153    if (request->canOutlivePage() == DoNotOutlivePage && (priority > Low || !url.protocolInHTTPFamily() || !hadRequests)) {
    143154        // Try to request important resources immediately
    144155        host->servePendingRequests(priority);
     
    249260
    250261    scheduleServePendingRequests();
    251    
    252     ASSERT(docLoader->requestCount() == (docLoader->loadInProgress() ? 1 : 0));
    253262}
    254263
     
    347356        }
    348357
    349         RefPtr<SubresourceLoader> loader = SubresourceLoader::create(docLoader->doc()->frame(),
    350             this, resourceRequest, request->shouldDoSecurityCheck(), request->sendResourceLoadCallbacks());
     358        RefPtr<SubresourceLoader> loader = SubresourceLoader::create(request->frame(),
     359            this, resourceRequest, request->shouldDoSecurityCheck(), request->canOutlivePage(), request->sendResourceLoadCallbacks());
    351360        if (loader) {
    352361            m_requestsLoading.add(loader.release(), request);
     
    551560    for (RequestQueue::iterator it = requestsPending.begin(); it != end; ++it) {
    552561        Request* request = *it;
    553         if (request->docLoader() == docLoader) {
     562        if (request->canOutlivePage() == DoNotOutlivePage && request->docLoader() == docLoader) {
    554563            cache()->remove(request->cachedResource());
    555564            delete request;
     
    571580    for (RequestMap::iterator i = m_requestsLoading.begin(); i != end; ++i) {
    572581        Request* r = i->second;
    573         if (r->docLoader() == docLoader)
     582        if (r->canOutlivePage() == DoNotOutlivePage && r->docLoader() == docLoader)
    574583            loadersToCancel.append(i->first.get());
    575584    }
Note: See TracChangeset for help on using the changeset viewer.