Changeset 246043 in webkit


Ignore:
Timestamp:
Jun 3, 2019 12:39:03 PM (5 years ago)
Author:
aestes@apple.com
Message:

Memory-cached main resources continue to load after the client decides a content policy of PolicyAction::Download
https://bugs.webkit.org/show_bug.cgi?id=198469
<rdar://problem/50512713>

Reviewed by Youenn Fablet.

Source/WebCore:

When a document is loaded from the memory cache it does not have a main resource loader, but
DocumentLoader::continueAfterContentPolicy relies on being able to call
ResourceLoader::didFail on the main resource loader to cancel the provisional navigation
when the client decides a content policy of PolicyAction::Download.

This means that memory-cached main resources continue to load even after WebKit has started
to download the main resource. The expected behavior is for the provisional navigation to
fail once the download starts, like what happens when there is a main resource loader.

This patch teaches DocumentLoader::continueAfterContentPolicy to call
stopLoadingForPolicyChange() in the case of a null main resource loader. This will dispatch
didFailProvisionalNavigation and remove the DocumentLoader as a client of its
CachedRawResource to prevent it from delivering any cached data.

Added a new API test.

  • loader/DocumentLoader.cpp:

(WebCore::DocumentLoader::continueAfterContentPolicy):

Tools:

  • TestWebKitAPI/Tests/WebKitCocoa/Download.mm:

(-[TestDownloadNavigationResponseFromMemoryCacheDelegate webView:didStartProvisionalNavigation:]):
(-[TestDownloadNavigationResponseFromMemoryCacheDelegate webView:didFailProvisionalNavigation:withError:]):
(-[TestDownloadNavigationResponseFromMemoryCacheDelegate webView:didFinishNavigation:]):
(-[TestDownloadNavigationResponseFromMemoryCacheDelegate _downloadDidStart:]):
(-[TestDownloadNavigationResponseFromMemoryCacheDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
(TEST):

  • TestWebKitAPI/cocoa/TestProtocol.h:
  • TestWebKitAPI/cocoa/TestProtocol.mm:

(+[TestProtocol additionalResponseHeaders]):
(+[TestProtocol setAdditionalResponseHeaders:]):
(-[TestProtocol startLoading]):

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r246042 r246043  
     12019-06-02  Andy Estes  <aestes@apple.com>
     2
     3        Memory-cached main resources continue to load after the client decides a content policy of PolicyAction::Download
     4        https://bugs.webkit.org/show_bug.cgi?id=198469
     5        <rdar://problem/50512713>
     6
     7        Reviewed by Youenn Fablet.
     8
     9        When a document is loaded from the memory cache it does not have a main resource loader, but
     10        DocumentLoader::continueAfterContentPolicy relies on being able to call
     11        ResourceLoader::didFail on the main resource loader to cancel the provisional navigation
     12        when the client decides a content policy of PolicyAction::Download.
     13
     14        This means that memory-cached main resources continue to load even after WebKit has started
     15        to download the main resource. The expected behavior is for the provisional navigation to
     16        fail once the download starts, like what happens when there is a main resource loader.
     17
     18        This patch teaches DocumentLoader::continueAfterContentPolicy to call
     19        stopLoadingForPolicyChange() in the case of a null main resource loader. This will dispatch
     20        didFailProvisionalNavigation and remove the DocumentLoader as a client of its
     21        CachedRawResource to prevent it from delivering any cached data.
     22
     23        Added a new API test.
     24
     25        * loader/DocumentLoader.cpp:
     26        (WebCore::DocumentLoader::continueAfterContentPolicy):
     27
    1282019-06-03  Timothy Hatcher  <timothy@apple.com>
    229
  • trunk/Source/WebCore/loader/DocumentLoader.cpp

    r245873 r246043  
    943943            frameLoader()->client().convertMainResourceLoadToDownload(this, sessionID, m_request, m_response);
    944944
    945         // It might have gone missing
    946         if (mainResourceLoader())
     945        // The main resource might be loading from the memory cache, or its loader might have gone missing.
     946        if (mainResourceLoader()) {
    947947            static_cast<ResourceLoader*>(mainResourceLoader())->didFail(interruptedForPolicyChangeError());
     948            return;
     949        }
     950
     951        // We must stop loading even if there is no main resource loader. Otherwise, we might remain
     952        // the client of a CachedRawResource that will continue to send us data.
     953        stopLoadingForPolicyChange();
    948954        return;
    949955    }
  • trunk/Tools/ChangeLog

    r246042 r246043  
     12019-06-02  Andy Estes  <aestes@apple.com>
     2
     3        Memory-cached main resources continue to load after the client decides a content policy of PolicyAction::Download
     4        https://bugs.webkit.org/show_bug.cgi?id=198469
     5        <rdar://problem/50512713>
     6
     7        Reviewed by Youenn Fablet.
     8
     9        * TestWebKitAPI/Tests/WebKitCocoa/Download.mm:
     10        (-[TestDownloadNavigationResponseFromMemoryCacheDelegate webView:didStartProvisionalNavigation:]):
     11        (-[TestDownloadNavigationResponseFromMemoryCacheDelegate webView:didFailProvisionalNavigation:withError:]):
     12        (-[TestDownloadNavigationResponseFromMemoryCacheDelegate webView:didFinishNavigation:]):
     13        (-[TestDownloadNavigationResponseFromMemoryCacheDelegate _downloadDidStart:]):
     14        (-[TestDownloadNavigationResponseFromMemoryCacheDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
     15        (TEST):
     16        * TestWebKitAPI/cocoa/TestProtocol.h:
     17        * TestWebKitAPI/cocoa/TestProtocol.mm:
     18        (+[TestProtocol additionalResponseHeaders]):
     19        (+[TestProtocol setAdditionalResponseHeaders:]):
     20        (-[TestProtocol startLoading]):
     21
    1222019-06-03  Timothy Hatcher  <timothy@apple.com>
    223
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/Download.mm

    r245901 r246043  
    3434#import "TestProtocol.h"
    3535#import "TestWKWebView.h"
     36#import <WebKit/WKErrorPrivate.h>
    3637#import <WebKit/WKNavigationDelegatePrivate.h>
    3738#import <WebKit/WKProcessPoolPrivate.h>
     
    915916} // namespace TestWebKitAPI
    916917
     918@interface TestDownloadNavigationResponseFromMemoryCacheDelegate : NSObject <WKNavigationDelegate, _WKDownloadDelegate>
     919@property (nonatomic) WKNavigationResponsePolicy responsePolicy;
     920@property (nonatomic, readonly) BOOL didFailProvisionalNavigation;
     921@property (nonatomic, readonly) BOOL didFinishNavigation;
     922@property (nonatomic, readonly) BOOL didStartDownload;
     923@end
     924
     925@implementation TestDownloadNavigationResponseFromMemoryCacheDelegate
     926
     927- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
     928{
     929    _didFailProvisionalNavigation = NO;
     930    _didFinishNavigation = NO;
     931    _didStartDownload = NO;
     932}
     933
     934- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
     935{
     936    EXPECT_EQ(_WKErrorCodeFrameLoadInterruptedByPolicyChange, error.code);
     937    EXPECT_FALSE(_didFinishNavigation);
     938    EXPECT_WK_STREQ(_WKLegacyErrorDomain, error.domain);
     939    _didFailProvisionalNavigation = YES;
     940    if (_responsePolicy != _WKNavigationResponsePolicyBecomeDownload || _didStartDownload)
     941        isDone = true;
     942}
     943
     944- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
     945{
     946    EXPECT_FALSE(_didFailProvisionalNavigation);
     947    _didFinishNavigation = YES;
     948    if (_responsePolicy != _WKNavigationResponsePolicyBecomeDownload || _didStartDownload)
     949        isDone = true;
     950}
     951
     952- (void)_downloadDidStart:(_WKDownload *)download
     953{
     954    _didStartDownload = YES;
     955    if (_didFailProvisionalNavigation || _didFinishNavigation)
     956        isDone = true;
     957}
     958
     959- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
     960{
     961    decisionHandler(_responsePolicy);
     962}
     963
     964@end
     965
     966TEST(WebKit, DownloadNavigationResponseFromMemoryCache)
     967{
     968    [TestProtocol registerWithScheme:@"http"];
     969    TestProtocol.additionalResponseHeaders = @{ @"Cache-Control" : @"max-age=3600" };
     970
     971    auto delegate = adoptNS([[TestDownloadNavigationResponseFromMemoryCacheDelegate alloc] init]);
     972    auto webView = adoptNS([[WKWebView alloc] init]);
     973    [webView setNavigationDelegate:delegate.get()];
     974    [webView configuration].processPool._downloadDelegate = delegate.get();
     975
     976    NSURL *firstURL = [NSURL URLWithString:@"http://bundle-html-file/simple"];
     977    [delegate setResponsePolicy:WKNavigationResponsePolicyAllow];
     978    [webView loadRequest:[NSURLRequest requestWithURL:firstURL]];
     979    isDone = false;
     980    TestWebKitAPI::Util::run(&isDone);
     981    EXPECT_FALSE([delegate didFailProvisionalNavigation]);
     982    EXPECT_FALSE([delegate didStartDownload]);
     983    EXPECT_TRUE([delegate didFinishNavigation]);
     984    EXPECT_WK_STREQ(firstURL.absoluteString, [webView URL].absoluteString);
     985
     986    NSURL *secondURL = [NSURL URLWithString:@"http://bundle-html-file/simple2"];
     987    [delegate setResponsePolicy:_WKNavigationResponsePolicyBecomeDownload];
     988    [webView loadRequest:[NSURLRequest requestWithURL:secondURL]];
     989    isDone = false;
     990    TestWebKitAPI::Util::run(&isDone);
     991    EXPECT_FALSE([delegate didFinishNavigation]);
     992    EXPECT_TRUE([delegate didFailProvisionalNavigation]);
     993    EXPECT_TRUE([delegate didStartDownload]);
     994    EXPECT_WK_STREQ(firstURL.absoluteString, [webView URL].absoluteString);
     995
     996    [delegate setResponsePolicy:WKNavigationResponsePolicyAllow];
     997    [webView loadRequest:[NSURLRequest requestWithURL:secondURL]];
     998    isDone = false;
     999    TestWebKitAPI::Util::run(&isDone);
     1000    EXPECT_FALSE([delegate didFailProvisionalNavigation]);
     1001    EXPECT_FALSE([delegate didStartDownload]);
     1002    EXPECT_TRUE([delegate didFinishNavigation]);
     1003    EXPECT_WK_STREQ(secondURL.absoluteString, [webView URL].absoluteString);
     1004
     1005    [delegate setResponsePolicy:WKNavigationResponsePolicyAllow];
     1006    [webView goBack];
     1007    isDone = false;
     1008    TestWebKitAPI::Util::run(&isDone);
     1009    EXPECT_FALSE([delegate didFailProvisionalNavigation]);
     1010    EXPECT_FALSE([delegate didStartDownload]);
     1011    EXPECT_TRUE([delegate didFinishNavigation]);
     1012    EXPECT_WK_STREQ(firstURL.absoluteString, [webView URL].absoluteString);
     1013
     1014    [delegate setResponsePolicy:_WKNavigationResponsePolicyBecomeDownload];
     1015    [webView loadRequest:[NSURLRequest requestWithURL:secondURL]];
     1016    isDone = false;
     1017    TestWebKitAPI::Util::run(&isDone);
     1018    EXPECT_FALSE([delegate didFinishNavigation]);
     1019    EXPECT_TRUE([delegate didFailProvisionalNavigation]);
     1020    EXPECT_TRUE([delegate didStartDownload]);
     1021    EXPECT_WK_STREQ(firstURL.absoluteString, [webView URL].absoluteString);
     1022
     1023    TestProtocol.additionalResponseHeaders = nil;
     1024    [TestProtocol unregister];
     1025}
     1026
    9171027#endif // PLATFORM(MAC) || PLATFORM(IOS)
  • trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.h

    r194950 r246043  
    3232+ (void)unregister;
    3333+ (NSString *)scheme;
     34@property (nonatomic, class, copy) NSDictionary<NSString *, NSString *> *additionalResponseHeaders;
    3435@end
    3536
  • trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.mm

    r243324 r246043  
    6969}
    7070
     71static NSDictionary<NSString *, NSString *> *additionalResponseHeaders;
     72
     73+ (NSDictionary<NSString *, NSString *> *)additionalResponseHeaders
     74{
     75    return additionalResponseHeaders;
     76}
     77
     78+ (void)setAdditionalResponseHeaders:(NSDictionary<NSString *, NSString *> *)additionalHeaders
     79{
     80    [additionalResponseHeaders autorelease];
     81    additionalResponseHeaders = [additionalHeaders copy];
     82}
     83
    7184static NSURL *createRedirectURL(NSString *query)
    7285{
     
    87100    }
    88101
     102    if ([requestURL.host isEqualToString:@"redirect"]) {
     103        NSData *data = [@"PASS" dataUsingEncoding:NSASCIIStringEncoding];
     104        auto response = adoptNS([[NSURLResponse alloc] initWithURL:requestURL MIMEType:@"text/html" expectedContentLength:data.length textEncodingName:nil]);
     105        [self.client URLProtocol:self wasRedirectedToRequest:[NSURLRequest requestWithURL:createRedirectURL(requestURL.query)] redirectResponse:response.get()];
     106        return;
     107    }
     108
    89109    NSData *data;
    90110    if ([requestURL.host isEqualToString:@"bundle-html-file"])
     
    93113        data = [@"PASS" dataUsingEncoding:NSASCIIStringEncoding];
    94114
    95     RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:requestURL MIMEType:@"text/html" expectedContentLength:data.length textEncodingName:nil]);
     115    NSMutableDictionary *responseHeaders = [NSMutableDictionary dictionaryWithCapacity:2];
     116    responseHeaders[@"Content-Type"] = @"text/html";
     117    responseHeaders[@"Content-Length"] = [NSString stringWithFormat:@"%tu", data.length];
     118    if (additionalResponseHeaders)
     119        [responseHeaders addEntriesFromDictionary:additionalResponseHeaders];
    96120
    97     if ([requestURL.host isEqualToString:@"redirect"]) {
    98         [self.client URLProtocol:self wasRedirectedToRequest:[NSURLRequest requestWithURL:createRedirectURL(requestURL.query)] redirectResponse:response.get()];
    99         return;
    100     }
     121    auto response = adoptNS([[NSHTTPURLResponse alloc] initWithURL:requestURL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:responseHeaders]);
    101122
    102123    [self.client URLProtocol:self didReceiveResponse:response.get() cacheStoragePolicy:NSURLCacheStorageNotAllowed];
Note: See TracChangeset for help on using the changeset viewer.