Changeset 230195 in webkit


Ignore:
Timestamp:
Apr 2, 2018 6:03:46 PM (6 years ago)
Author:
beidson@apple.com
Message:

Process swapping on navigation needs to handle server redirects.
<rdar://problem/38690465> and https://bugs.webkit.org/show_bug.cgi?id=184142

Reviewed by Alex Christensen.

Source/WebKit:

The same rules we apply to process swapping for basic navigations need to apply
to server redirects as well.

There's three interesting cases we need to support that are covered by new API tests:
1 - The initial load in a WKWebView redirects cross-origin.
2 - A WKWebView is showing content from a.com, we start a load to b.com, and that redirects to c.com
3 - A WKWebView is showing content from a.com, we start a load to a.com, that that redirects to b.com.

Supporting all 3 of these brought their own little challenges.

By teaching Navigation objects more about redirects I was able to support all 3 cases.

  • UIProcess/API/APINavigation.cpp:

(API::Navigation::Navigation):
(API::Navigation::setCurrentRequest):
(API::Navigation::appendRedirectionURL):
(API::Navigation::loggingString const):
(API::Navigation::loggingURL const): Deleted.

  • UIProcess/API/APINavigation.h:

(API::Navigation::originalRequest const):
(API::Navigation::currentRequest const):
(API::Navigation::currentRequestProcessIdentifier const):
(API::Navigation::setCurrentRequestIsRedirect):
(API::Navigation::currentRequestIsRedirect const):
(API::Navigation::request const): Deleted.

  • UIProcess/API/Cocoa/WKNavigation.mm:

(-[WKNavigation _request]):

  • UIProcess/WebPageProxy.cpp:

(WebKit::WebPageProxy::receivedPolicyDecision):
(WebKit::WebPageProxy::continueNavigationInNewProcess): If this continued navigation is currently in a server

redirect, save off a lambda to synthesize a "did receive server redirect" callback once the new WebProcess is running.

(WebKit::WebPageProxy::didCreateMainFrame):
(WebKit::WebPageProxy::didStartProvisionalLoadForFrame): Possibly ignore this notification if it is really a

cross-origin redirect that is just starting back up in a new WebProcess.

(WebKit::WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame):
(WebKit::WebPageProxy::didCommitLoadForFrame):
(WebKit::WebPageProxy::decidePolicyForNavigationAction):
(WebKit::WebPageProxy::resetStateAfterProcessExited): Do not clear pageLoadState if the process is exitting for

a navigation swap, as we will need to pick up where we left off when the load continues in a new WebProcess.

  • UIProcess/WebPageProxy.h:
  • UIProcess/WebPageProxy.messages.in:
  • UIProcess/WebProcessPool.cpp:

(WebKit::WebProcessPool::processForNavigation): If a process has never committed any provisional load, it can always

be used to continue a navigation.

  • UIProcess/WebProcessPool.h:
  • UIProcess/WebProcessProxy.h:

(WebKit::WebProcessProxy::didCommitProvisionalLoad):
(WebKit::WebProcessProxy::hasCommittedAnyProvisionalLoads const):

  • WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:

(WebKit::WebFrameLoaderClient::dispatchDidReceiveServerRedirectForProvisionalLoad):
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):

Tools:

  • TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:

(-[PSONNavigationDelegate webView:didFinishNavigation:]):
(-[PSONNavigationDelegate webView:decidePolicyForNavigationAction:decisionHandler:]):
(-[PSONNavigationDelegate webView:didReceiveServerRedirectForProvisionalNavigation:]):
(-[PSONScheme addRedirectFromURLString:toURLString:]):
(-[PSONScheme webView:startURLSchemeTask:]):

Location:
trunk
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r230194 r230195  
     12018-04-02  Brady Eidson  <beidson@apple.com>
     2
     3        Process swapping on navigation needs to handle server redirects.
     4        <rdar://problem/38690465> and https://bugs.webkit.org/show_bug.cgi?id=184142
     5
     6        Reviewed by Alex Christensen.
     7
     8        The same rules we apply to process swapping for basic navigations need to apply
     9        to server redirects as well.
     10
     11        There's three interesting cases we need to support that are covered by new API tests:
     12        1 - The initial load in a WKWebView redirects cross-origin.
     13        2 - A WKWebView is showing content from a.com, we start a load to b.com, and that redirects to c.com
     14        3 - A WKWebView is showing content from a.com, we start a load to a.com, that that redirects to b.com.
     15
     16        Supporting all 3 of these brought their own little challenges.
     17
     18        By teaching Navigation objects more about redirects I was able to support all 3 cases.
     19
     20        * UIProcess/API/APINavigation.cpp:
     21        (API::Navigation::Navigation):
     22        (API::Navigation::setCurrentRequest):
     23        (API::Navigation::appendRedirectionURL):
     24        (API::Navigation::loggingString const):
     25        (API::Navigation::loggingURL const): Deleted.
     26        * UIProcess/API/APINavigation.h:
     27        (API::Navigation::originalRequest const):
     28        (API::Navigation::currentRequest const):
     29        (API::Navigation::currentRequestProcessIdentifier const):
     30        (API::Navigation::setCurrentRequestIsRedirect):
     31        (API::Navigation::currentRequestIsRedirect const):
     32        (API::Navigation::request const): Deleted.
     33
     34        * UIProcess/API/Cocoa/WKNavigation.mm:
     35        (-[WKNavigation _request]):
     36
     37        * UIProcess/WebPageProxy.cpp:
     38        (WebKit::WebPageProxy::receivedPolicyDecision):
     39        (WebKit::WebPageProxy::continueNavigationInNewProcess): If this continued navigation is currently in a server
     40          redirect, save off a lambda to synthesize a "did receive server redirect" callback once the new WebProcess is running.
     41        (WebKit::WebPageProxy::didCreateMainFrame):
     42        (WebKit::WebPageProxy::didStartProvisionalLoadForFrame): Possibly ignore this notification if it is really a
     43          cross-origin redirect that is just starting back up in a new WebProcess.
     44        (WebKit::WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame):
     45        (WebKit::WebPageProxy::didCommitLoadForFrame):
     46        (WebKit::WebPageProxy::decidePolicyForNavigationAction):
     47        (WebKit::WebPageProxy::resetStateAfterProcessExited): Do not clear pageLoadState if the process is exitting for
     48          a navigation swap, as we will need to pick up where we left off when the load continues in a new WebProcess.
     49        * UIProcess/WebPageProxy.h:
     50        * UIProcess/WebPageProxy.messages.in:
     51
     52        * UIProcess/WebProcessPool.cpp:
     53        (WebKit::WebProcessPool::processForNavigation): If a process has never committed any provisional load, it can always
     54          be used to continue a navigation.
     55        * UIProcess/WebProcessPool.h:
     56
     57        * UIProcess/WebProcessProxy.h:
     58        (WebKit::WebProcessProxy::didCommitProvisionalLoad):
     59        (WebKit::WebProcessProxy::hasCommittedAnyProvisionalLoads const):
     60
     61        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
     62        (WebKit::WebFrameLoaderClient::dispatchDidReceiveServerRedirectForProvisionalLoad):
     63        (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
     64
    1652018-04-02  Eric Carlson  <eric.carlson@apple.com>
    266
  • trunk/Source/WebKit/UIProcess/API/APINavigation.cpp

    r230191 r230195  
    4242Navigation::Navigation(WebNavigationState& state, WebCore::ResourceRequest&& request)
    4343    : m_navigationID(state.generateNavigationID())
    44     , m_request(WTFMove(request))
     44    , m_originalRequest(WTFMove(request))
     45    , m_currentRequest(m_originalRequest)
    4546{
    46     m_redirectChain.append(m_request.url());
     47    m_redirectChain.append(m_originalRequest.url());
    4748}
    4849
    4950Navigation::Navigation(WebNavigationState& state, WebBackForwardListItem& item, FrameLoadType backForwardFrameLoadType)
    5051    : m_navigationID(state.generateNavigationID())
     52    , m_originalRequest(item.url())
     53    , m_currentRequest(m_originalRequest)
    5154    , m_backForwardListItem(&item)
    5255    , m_backForwardFrameLoadType(backForwardFrameLoadType)
     
    5861}
    5962
    60 void Navigation::appendRedirectionURL(const WebCore::URL& url)
     63void Navigation::setCurrentRequest(ResourceRequest&& request, ProcessIdentifier processIdentifier)
     64{
     65    m_currentRequest = WTFMove(request);
     66    m_currentRequestProcessIdentifier = processIdentifier;
     67}
     68
     69void Navigation::appendRedirectionURL(const URL& url)
    6170{
    6271    if (m_redirectChain.isEmpty() || m_redirectChain.last() != url)
     
    6574
    6675#if !LOG_DISABLED
    67 WTF::String Navigation::loggingURL() const
     76WTF::String Navigation::loggingString() const
    6877{
    69     return m_backForwardListItem ? m_backForwardListItem->url() : m_request.url().string();
     78    return makeString("Most recent URL: ", m_currentRequest.url().string(), " Back/forward list item URL: '", m_backForwardListItem ? m_backForwardListItem->url() : String { }, String::format("' (%p)", m_backForwardListItem.get()));
    7079}
    7180#endif
  • trunk/Source/WebKit/UIProcess/API/APINavigation.h

    r230191 r230195  
    2727
    2828#include "APIObject.h"
     29#include <WebCore/Process.h>
    2930#include <WebCore/ResourceRequest.h>
    3031#include <wtf/Ref.h>
     
    6364    uint64_t navigationID() const { return m_navigationID; }
    6465
    65     const WebCore::ResourceRequest& request() const { return m_request; }
     66    const WebCore::ResourceRequest& originalRequest() const { return m_originalRequest; }
     67    void setCurrentRequest(WebCore::ResourceRequest&&, WebCore::ProcessIdentifier);
     68    const WebCore::ResourceRequest& currentRequest() const { return m_currentRequest; }
     69    std::optional<WebCore::ProcessIdentifier> currentRequestProcessIdentifier() const { return m_currentRequestProcessIdentifier; }
     70
     71    void setCurrentRequestIsRedirect(bool isRedirect) { m_isRedirect = isRedirect; }
     72    bool currentRequestIsRedirect() const { return m_isRedirect; }
     73
    6674    WebKit::WebBackForwardListItem* backForwardListItem() { return m_backForwardListItem.get(); }
    6775    std::optional<WebCore::FrameLoadType> backForwardFrameLoadType() const { return m_backForwardFrameLoadType; }
     
    8391
    8492#if !LOG_DISABLED
    85     WTF::String loggingURL() const;
     93    WTF::String loggingString() const;
    8694#endif
    8795
     
    92100
    93101    uint64_t m_navigationID;
    94     WebCore::ResourceRequest m_request;
     102    WebCore::ResourceRequest m_originalRequest;
     103    WebCore::ResourceRequest m_currentRequest;
     104    std::optional<WebCore::ProcessIdentifier> m_currentRequestProcessIdentifier;
    95105    Vector<WebCore::URL> m_redirectChain;
    96106    bool m_wasUserInitiated { true };
    97107    bool m_shouldForceDownload { false };
     108    bool m_isRedirect { false };
    98109
    99110    RefPtr<WebKit::WebBackForwardListItem> m_backForwardListItem;
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKNavigation.mm

    r230191 r230195  
    4444- (NSURLRequest *)_request
    4545{
    46     return _navigation->request().nsURLRequest(WebCore::DoNotUpdateHTTPBody);
     46    return _navigation->originalRequest().nsURLRequest(WebCore::DoNotUpdateHTTPBody);
    4747}
    4848
  • trunk/Source/WebKit/UIProcess/WebPageProxy.cpp

    r230191 r230195  
    23532353        if (action == PolicyAction::Use && navigation) {
    23542354            auto proposedProcess = process().processPool().processForNavigation(*this, *navigation, action);
     2355
    23552356            if (proposedProcess.ptr() != &process()) {
    2356                 LOG(Loading, "Switching to new process for navigation %" PRIu64 " to url '%s' (WebBackForwardListItem %p)", navigation->navigationID(), navigation->loggingURL().utf8().data(), navigation->backForwardListItem());
     2357                LOG(Loading, "Switching from process %i to new process for navigation %" PRIu64 " '%s'", processIdentifier(), navigation->navigationID(), navigation->loggingString().utf8().data());
    23572358
    23582359                RunLoop::main().dispatch([this, protectedThis = makeRef(*this), navigation = makeRef(*navigation), proposedProcess = WTFMove(proposedProcess)]() mutable {
     
    23682369void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, Ref<WebProcessProxy>&& process)
    23692370{
    2370     LOG(Loading, "Continuing navigation %" PRIu64 " to URL %s in a new web process", navigation.navigationID(), navigation.loggingURL().utf8().data());
    2371 
     2371    LOG(Loading, "Continuing navigation %" PRIu64 " '%s' in a new web process", navigation.navigationID(), navigation.loggingString().utf8().data());
     2372
     2373    ASSERT(m_process.ptr() != process.ptr());
    23722374    attachToProcessForNavigation(WTFMove(process));
    23732375
     
    23852387
    23862388    // FIXME: Work out timing of responding with the last policy delegate, etc
    2387     loadRequestWithNavigation(navigation, ResourceRequest { navigation.request() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, NavigationPolicyCheck::Bypass);
     2389    ASSERT(!navigation.currentRequest().isEmpty());
     2390    loadRequestWithNavigation(navigation, ResourceRequest { navigation.currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, NavigationPolicyCheck::Bypass);
     2391
     2392    // Normally, notification of a server redirect comes from the WebContent process.
     2393    // If we are process swapping in response to a server redirect then that notification will not come from the new WebContent process.
     2394    // In this case we have the UIProcess synthesize the redirect notification at the appropriate time.
     2395    if (navigation.currentRequestIsRedirect()) {
     2396        ASSERT(!m_mainFrame);
     2397        m_mainFrameCreationHandler = [this, protectedThis = makeRef(*this), navigation = makeRef(navigation), request =  navigation.currentRequest()]() mutable {
     2398            ASSERT(m_mainFrame);
     2399            m_mainFrame->frameLoadState().didStartProvisionalLoad(request.url());
     2400            didReceiveServerRedirectForProvisionalLoadForFrame(m_mainFrame->frameID(), navigation->navigationID(), WTFMove(request), { });
     2401        };
     2402    }
    23882403}
    23892404
     
    31943209    // Add the frame to the process wide map.
    31953210    m_process->frameCreated(frameID, m_mainFrame.get());
     3211
     3212    if (m_mainFrameCreationHandler) {
     3213        m_mainFrameCreationHandler();
     3214        m_mainFrameCreationHandler = nullptr;
     3215    }
    31963216}
    31973217
     
    32703290    PageClientProtector protector(m_pageClient);
    32713291
    3272     auto transaction = m_pageLoadState.transaction();
    3273 
    3274     m_pageLoadState.clearPendingAPIRequestURL(transaction);
    3275 
    32763292    WebFrameProxy* frame = m_process->webFrame(frameID);
    32773293    MESSAGE_CHECK(frame);
     
    32823298    if (frame->isMainFrame() && navigationID)
    32833299        navigation = &navigationState().navigation(navigationID);
     3300
     3301    // If this seemingly new load is actually continuing a server redirect for a previous navigation in a new process,
     3302    // then we ignore this notification.
     3303    if (navigation && navigation->currentRequestIsRedirect()) {
     3304        auto navigationProcessIdentifier = navigation->currentRequestProcessIdentifier();
     3305        if (navigationProcessIdentifier && *navigationProcessIdentifier != m_process->coreProcessIdentifier())
     3306            return;
     3307    }
     3308
     3309    LOG(Loading, "WebPageProxy::didStartProvisionalLoadForFrame to frameID %" PRIu64 ", navigationID %" PRIu64 ", url %s", frameID, navigationID, url.string().utf8().data());
     3310
     3311    auto transaction = m_pageLoadState.transaction();
     3312
     3313    m_pageLoadState.clearPendingAPIRequestURL(transaction);
    32843314
    32853315    if (frame->isMainFrame()) {
     
    33033333}
    33043334
    3305 void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::URL&& url, const UserData& userData)
    3306 {
     3335void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, ResourceRequest&& request, const UserData& userData)
     3336{
     3337    LOG(Loading, "WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame to frameID %" PRIu64 ", navigationID %" PRIu64 ", url %s", frameID, navigationID, request.url().string().utf8().data());
     3338
    33073339    PageClientProtector protector(m_pageClient);
    33083340
    33093341    WebFrameProxy* frame = m_process->webFrame(frameID);
    33103342    MESSAGE_CHECK(frame);
    3311     MESSAGE_CHECK_URL(url);
     3343    MESSAGE_CHECK_URL(request.url());
    33123344
    33133345    // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
     
    33153347    if (navigationID) {
    33163348        navigation = &navigationState().navigation(navigationID);
    3317         navigation->appendRedirectionURL(url);
     3349        navigation->appendRedirectionURL(request.url());
    33183350    }
    33193351
     
    33213353
    33223354    if (frame->isMainFrame())
    3323         m_pageLoadState.didReceiveServerRedirectForProvisionalLoad(transaction, url);
    3324 
    3325     frame->didReceiveServerRedirectForProvisionalLoad(url);
     3355        m_pageLoadState.didReceiveServerRedirectForProvisionalLoad(transaction, request.url());
     3356
     3357    frame->didReceiveServerRedirectForProvisionalLoad(request.url());
    33263358
    33273359    m_pageLoadState.commitChanges();
     
    34433475    if (frame->isMainFrame() && navigationID)
    34443476        navigation = &navigationState().navigation(navigationID);
     3477
     3478    m_process->didCommitProvisionalLoad();
    34453479
    34463480#if PLATFORM(IOS)
     
    37923826void WebPageProxy::decidePolicyForNavigationAction(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, NavigationActionData&& navigationActionData, const FrameInfoData& originatingFrameInfoData, uint64_t originatingPageID, const WebCore::ResourceRequest& originalRequest, ResourceRequest&& request, uint64_t listenerID, const UserData& userData)
    37933827{
    3794     LOG(Loading, "WebPageProxy::didStartProvisionalLoadForFrame - Target url %s", originalRequest.url().string().utf8().data());
     3828    LOG(Loading, "WebPageProxy::decidePolicyForNavigationAction - Original URL %s, current target URL %s", originalRequest.url().string().utf8().data(), request.url().string().utf8().data());
    37953829
    37963830    PageClientProtector protector(m_pageClient);
     
    38073841    MESSAGE_CHECK_URL(originalRequest.url());
    38083842   
    3809     uint64_t newNavigationID { 0 };
    3810     Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID, PolicyListenerType::NavigationAction);
    38113843    Ref<API::Navigation> navigation = navigationID ? makeRef(m_navigationState->navigation(navigationID)) : m_navigationState->createLoadRequestNavigation(ResourceRequest(request));
    38123844
    3813     newNavigationID = navigation->navigationID();
     3845    uint64_t newNavigationID = navigation->navigationID();
    38143846    navigation->setWasUserInitiated(!!navigationActionData.userGestureTokenIdentifier);
    38153847    navigation->setShouldForceDownload(!navigationActionData.downloadAttribute.isNull());
     3848    navigation->setCurrentRequest(ResourceRequest(request), m_process->coreProcessIdentifier());
     3849    navigation->setCurrentRequestIsRedirect(navigationActionData.isRedirect);
    38163850    navigation->setIsCrossOriginWindowOpenNavigation(navigationActionData.isCrossOriginWindowOpenNavigation);
    38173851    navigation->setOpener(navigationActionData.opener);
     3852
     3853    auto listener = makeRef(frame->setUpPolicyListenerProxy(listenerID, PolicyListenerType::NavigationAction));
    38183854    listener->setNavigation(WTFMove(navigation));
    38193855
     
    58045840#endif
    58055841
    5806     PageLoadState::Transaction transaction = m_pageLoadState.transaction();
    5807     m_pageLoadState.reset(transaction);
    5808 
     5842    if (terminationReason != ProcessTerminationReason::NavigationSwap) {
     5843        PageLoadState::Transaction transaction = m_pageLoadState.transaction();
     5844        m_pageLoadState.reset(transaction);
     5845    }
     5846
     5847    // FIXME: <rdar://problem/38676604> In case of process swaps, the old process should gracefully suspend instead of terminating.
    58095848    m_process->processTerminated();
    58105849}
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r230191 r230195  
    13401340
    13411341    void didStartProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::URL&&, WebCore::URL&& unreachableURL, const UserData&);
    1342     void didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::URL&&, const UserData&);
     1342    void didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::ResourceRequest&&, const UserData&);
    13431343    void willPerformClientRedirectForFrame(uint64_t frameID, const String& url, double delay);
    13441344    void didCancelClientRedirectForFrame(uint64_t frameID);
     
    17781778
    17791779    RefPtr<WebFrameProxy> m_mainFrame;
     1780    Function<void()> m_mainFrameCreationHandler;
     1781
    17801782    RefPtr<WebFrameProxy> m_focusedFrame;
    17811783    RefPtr<WebFrameProxy> m_frameSetLargestFrame;
  • trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in

    r230191 r230195  
    117117    # Frame load messages
    118118    DidStartProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::URL url, WebCore::URL unreachableURL, WebKit::UserData userData)
    119     DidReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::URL url, WebKit::UserData userData)
     119    DidReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::ResourceRequest request, WebKit::UserData userData)
    120120    WillPerformClientRedirectForFrame(uint64_t frameID, String url, double delay)
    121121    DidCancelClientRedirectForFrame(uint64_t frameID)
  • trunk/Source/WebKit/UIProcess/WebProcessPool.cpp

    r230191 r230195  
    19861986        return page.process();
    19871987
     1988    if (!page.process().hasCommittedAnyProvisionalLoads())
     1989        return page.process();
     1990
    19881991    // FIXME: We should support process swap when a window has an opener.
    19891992    if (navigation.opener())
     
    19951998    }
    19961999
    1997     auto targetURL = navigation.request().url();
     2000    auto targetURL = navigation.currentRequest().url();
    19982001    auto url = URL { ParsedURLString, page.pageLoadState().url() };
    1999     if (!url.isValid() || url.isBlankURL() || protocolHostAndPortAreEqual(url, targetURL))
     2002    if (!url.isValid() || url.isEmpty() || url.isBlankURL() || protocolHostAndPortAreEqual(url, targetURL))
    20002003        return page.process();
    20012004
  • trunk/Source/WebKit/UIProcess/WebProcessPool.h

    r230191 r230195  
    7979class InjectedBundleClient;
    8080class LegacyContextHistoryClient;
     81class Navigation;
    8182class PageConfiguration;
    8283}
  • trunk/Source/WebKit/UIProcess/WebProcessProxy.h

    r230191 r230195  
    206206    void checkProcessLocalPortForActivity(const WebCore::MessagePortIdentifier&, CompletionHandler<void(WebCore::MessagePortChannelProvider::HasActivity)>&&);
    207207
     208    void didCommitProvisionalLoad() { m_hasCommittedAnyProvisionalLoads = true; }
     209    bool hasCommittedAnyProvisionalLoads() const { return m_hasCommittedAnyProvisionalLoads; }
     210
    208211protected:
    209212    static uint64_t generatePageID();
     
    330333    HashMap<uint64_t, Function<void()>> m_messageBatchDeliveryCompletionHandlers;
    331334    HashMap<uint64_t, CompletionHandler<void(WebCore::MessagePortChannelProvider::HasActivity)>> m_localPortActivityCompletionHandlers;
     335
     336    bool m_hasCommittedAnyProvisionalLoads { false };
    332337};
    333338
  • trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp

    r230191 r230195  
    3636#include "InjectedBundleDOMWindowExtension.h"
    3737#include "InjectedBundleNavigationAction.h"
     38#include "Logging.h"
    3839#include "NavigationActionData.h"
    3940#include "NetworkConnectionToWebProcessMessages.h"
     
    307308    RefPtr<API::Object> userData;
    308309
     310    LOG(Loading, "WebProcess %i - dispatchDidReceiveServerRedirectForProvisionalLoad to request url %s", getpid(), documentLoader.request().url().string().utf8().data());
     311
    309312    // Notify the bundle client.
    310313    webPage->injectedBundleLoaderClient().didReceiveServerRedirectForProvisionalLoadForFrame(*webPage, *m_frame, userData);
    311314
    312315    // Notify the UIProcess.
    313     webPage->send(Messages::WebPageProxy::DidReceiveServerRedirectForProvisionalLoadForFrame(m_frame->frameID(), documentLoader.navigationID(), documentLoader.url(), UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())));
     316    webPage->send(Messages::WebPageProxy::DidReceiveServerRedirectForProvisionalLoadForFrame(m_frame->frameID(), documentLoader.navigationID(), documentLoader.request(), UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())));
    314317}
    315318
     
    818821        return;
    819822    }
     823
     824    LOG(Loading, "WebProcess %i - dispatchDecidePolicyForNavigationAction to request url %s", getpid(), request.url().string().utf8().data());
    820825
    821826    m_isDecidingNavigationPolicyDecision = true;
  • trunk/Tools/ChangeLog

    r230192 r230195  
     12018-04-02  Brady Eidson  <beidson@apple.com>
     2
     3        Process swapping on navigation needs to handle server redirects.
     4        <rdar://problem/38690465> and https://bugs.webkit.org/show_bug.cgi?id=184142
     5
     6        Reviewed by Alex Christensen.
     7
     8        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
     9        (-[PSONNavigationDelegate webView:didFinishNavigation:]):
     10        (-[PSONNavigationDelegate webView:decidePolicyForNavigationAction:decisionHandler:]):
     11        (-[PSONNavigationDelegate webView:didReceiveServerRedirectForProvisionalNavigation:]):
     12        (-[PSONScheme addRedirectFromURLString:toURLString:]):
     13        (-[PSONScheme webView:startURLSchemeTask:]):
     14
    1152018-04-02  Daniel Bates  <dabates@apple.com>
    216
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm

    r230191 r230195  
    2929#import "Test.h"
    3030#import <WebKit/WKNavigationDelegate.h>
     31#import <WebKit/WKNavigationPrivate.h>
    3132#import <WebKit/WKPreferencesPrivate.h>
    3233#import <WebKit/WKProcessPoolPrivate.h>
     
    4546#import <wtf/Deque.h>
    4647#import <wtf/HashMap.h>
     48#import <wtf/HashSet.h>
    4749#import <wtf/RetainPtr.h>
    4850#import <wtf/Vector.h>
     
    5860static RetainPtr<NSMutableArray> receivedMessages = adoptNS([@[] mutableCopy]);
    5961static bool receivedMessage;
     62static bool serverRedirected;
     63static HashSet<pid_t> seenPIDs;
    6064@interface PSONMessageHandler : NSObject <WKScriptMessageHandler>
    6165@end
     
    7680- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
    7781{
     82    seenPIDs.add([webView _webProcessIdentifier]);
    7883    done = true;
    7984}
     
    8287{
    8388    ++numberOfDecidePolicyCalls;
     89    seenPIDs.add([webView _webProcessIdentifier]);
    8490    decisionHandler(WKNavigationActionPolicyAllow);
     91}
     92
     93- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
     94{
     95    seenPIDs.add([webView _webProcessIdentifier]);
     96    serverRedirected = true;
    8597}
    8698
     
    118130@interface PSONScheme : NSObject <WKURLSchemeHandler> {
    119131    const char* _bytes;
     132    HashMap<String, String> _redirects;
    120133}
    121134- (instancetype)initWithBytes:(const char*)bytes;
     135- (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString;
    122136@end
    123137
     
    131145}
    132146
     147- (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString
     148{
     149    _redirects.set(sourceURLString, destinationURLString);
     150}
     151
    133152- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
    134153{
    135     RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:1 textEncodingName:nil]);
     154    NSURL *finalURL = task.request.URL;
     155    auto target = _redirects.get(task.request.URL.absoluteString);
     156    if (!target.isEmpty()) {
     157        auto redirectResponse = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:nil expectedContentLength:0 textEncodingName:nil]);
     158
     159        finalURL = [NSURL URLWithString:(NSString *)target];
     160        auto request = adoptNS([[NSURLRequest alloc] initWithURL:finalURL]);
     161
     162        [(id<WKURLSchemeTaskPrivate>)task _didPerformRedirection:redirectResponse.get() newRequest:request.get()];
     163    }
     164
     165    RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:finalURL MIMEType:@"text/html" expectedContentLength:1 textEncodingName:nil]);
    136166    [task didReceiveResponse:response.get()];
    137167
     
    445475#endif // PLATFORM(MAC)
    446476
     477TEST(ProcessSwap, ServerRedirectFromNewWebView)
     478{
     479    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
     480    processPoolConfiguration.get().processSwapsOnNavigation = YES;
     481    auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
     482
     483    auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
     484    [webViewConfiguration setProcessPool:processPool.get()];
     485    RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] init]);
     486    [handler addRedirectFromURLString:@"pson://host/main1.html" toURLString:@"psonredirected://host/main1.html"];
     487    [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
     488
     489    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
     490    auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
     491    [webView setNavigationDelegate:delegate.get()];
     492
     493    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
     494    [webView loadRequest:request];
     495
     496    TestWebKitAPI::Util::run(&serverRedirected);
     497    serverRedirected = false;
     498
     499    seenPIDs.add([webView _webProcessIdentifier]);
     500
     501    TestWebKitAPI::Util::run(&done);
     502    done = false;
     503
     504    seenPIDs.add([webView _webProcessIdentifier]);
     505
     506    EXPECT_FALSE(serverRedirected);
     507    EXPECT_EQ(2, numberOfDecidePolicyCalls);
     508    EXPECT_EQ(1u, seenPIDs.size());
     509}
     510
     511TEST(ProcessSwap, ServerRedirect)
     512{
     513    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
     514    processPoolConfiguration.get().processSwapsOnNavigation = YES;
     515    auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
     516
     517    auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
     518    [webViewConfiguration setProcessPool:processPool.get()];
     519    RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] init]);
     520    [handler1 addRedirectFromURLString:@"pson://host/main1.html" toURLString:@"psonredirected://host/main1.html"];
     521    [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"];
     522    RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
     523    [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"originalload"];
     524
     525    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
     526    auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
     527    [webView setNavigationDelegate:delegate.get()];
     528
     529    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"originalload://host/main1.html"]];
     530    [webView loadRequest:request];
     531
     532    TestWebKitAPI::Util::run(&done);
     533    done = false;
     534
     535    auto pidAfterFirstLoad = [webView _webProcessIdentifier];
     536
     537    EXPECT_EQ(1, numberOfDecidePolicyCalls);
     538    EXPECT_EQ(1u, seenPIDs.size());
     539    EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
     540
     541    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
     542    [webView loadRequest:request];
     543
     544    TestWebKitAPI::Util::run(&serverRedirected);
     545    serverRedirected = false;
     546
     547    seenPIDs.add([webView _webProcessIdentifier]);
     548
     549    TestWebKitAPI::Util::run(&done);
     550    done = false;
     551
     552    seenPIDs.add([webView _webProcessIdentifier]);
     553
     554    EXPECT_FALSE(serverRedirected);
     555    EXPECT_EQ(3, numberOfDecidePolicyCalls);
     556    EXPECT_EQ(2u, seenPIDs.size());
     557}
     558
     559TEST(ProcessSwap, ServerRedirect2)
     560{
     561    // This tests a load that *starts out* to the same origin as the previous load, but then redirects to a new origin.
     562    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
     563    processPoolConfiguration.get().processSwapsOnNavigation = YES;
     564    auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
     565
     566    auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
     567    [webViewConfiguration setProcessPool:processPool.get()];
     568    RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] init]);
     569    [handler1 addRedirectFromURLString:@"pson://host/main2.html" toURLString:@"psonredirected://host/main1.html"];
     570    [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"];
     571    RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
     572    [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"psonredirected"];
     573
     574    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
     575    auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
     576    [webView setNavigationDelegate:delegate.get()];
     577
     578    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
     579    [webView loadRequest:request];
     580
     581    TestWebKitAPI::Util::run(&done);
     582    done = false;
     583
     584    auto pidAfterFirstLoad = [webView _webProcessIdentifier];
     585
     586    EXPECT_FALSE(serverRedirected);
     587    EXPECT_EQ(1, numberOfDecidePolicyCalls);
     588    EXPECT_EQ(1u, seenPIDs.size());
     589    EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
     590
     591    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main2.html"]];
     592    [webView loadRequest:request];
     593
     594    TestWebKitAPI::Util::run(&serverRedirected);
     595    serverRedirected = false;
     596
     597    seenPIDs.add([webView _webProcessIdentifier]);
     598
     599    TestWebKitAPI::Util::run(&done);
     600    done = false;
     601
     602    seenPIDs.add([webView _webProcessIdentifier]);
     603
     604    EXPECT_FALSE(serverRedirected);
     605    EXPECT_EQ(3, numberOfDecidePolicyCalls);
     606    EXPECT_EQ(2u, seenPIDs.size());
     607}
     608
     609
    447610#endif // WK_API_ENABLED
Note: See TracChangeset for help on using the changeset viewer.