Changeset 244573 in webkit


Ignore:
Timestamp:
Apr 23, 2019 5:24:27 PM (5 years ago)
Author:
aestes@apple.com
Message:

[iOS] QuickLook documents loaded from file: URLs should be allowed to perform same-document navigations
https://bugs.webkit.org/show_bug.cgi?id=196749
<rdar://problem/35773454>

Reviewed by Daniel Bates.

Source/WebCore:

QuickLook previews are in a non-local origin defined by a unique x-apple-ql-id: URL, which
isolates the origin that hosted the document from the document preview itself. When a
QuickLook document is loaded as a file: URL, SecurityOrigin's protections against loading
local resources from non-local origins prevented navigations like location.reload() and
fragment navigations.

To allow reloads and same-document navigations in QuickLook documents loaded from file: URLs,
we should grant the QuickLook document's SecurityOrigin access to the file path that loaded
the preview.

Added a new API test.

  • dom/Document.cpp:

(WebCore::Document::applyQuickLookSandbox):

  • page/SecurityOrigin.cpp:

(WebCore::SecurityOrigin::createNonLocalWithAllowedFilePath):
(WebCore::SecurityOrigin::canDisplay const):

  • page/SecurityOrigin.h:

Tools:

Added a new QuickLook API test and added new expectations to existing QuickLook tests.

  • TestWebKitAPI/Tests/WebKitCocoa/QuickLook.mm:

(-[QuickLookDelegate webView:didStartProvisionalNavigation:]):
(-[QuickLookDelegate webView:didFinishNavigation:]):
(-[QuickLookDelegate _webView:didFailNavigation:withError:userInfo:]):
(-[QuickLookDelegate webView:didFailProvisionalNavigation:withError:]):
(runTest):
(runTestDecideBeforeLoading):
(runTestDecideAfterLoading):
(TEST):

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r244569 r244573  
     12019-04-23  Andy Estes  <aestes@apple.com>
     2
     3        [iOS] QuickLook documents loaded from file: URLs should be allowed to perform same-document navigations
     4        https://bugs.webkit.org/show_bug.cgi?id=196749
     5        <rdar://problem/35773454>
     6
     7        Reviewed by Daniel Bates.
     8
     9        QuickLook previews are in a non-local origin defined by a unique x-apple-ql-id: URL, which
     10        isolates the origin that hosted the document from the document preview itself. When a
     11        QuickLook document is loaded as a file: URL, SecurityOrigin's protections against loading
     12        local resources from non-local origins prevented navigations like location.reload() and
     13        fragment navigations.
     14
     15        To allow reloads and same-document navigations in QuickLook documents loaded from file: URLs,
     16        we should grant the QuickLook document's SecurityOrigin access to the file path that loaded
     17        the preview.
     18
     19        Added a new API test.
     20
     21        * dom/Document.cpp:
     22        (WebCore::Document::applyQuickLookSandbox):
     23        * page/SecurityOrigin.cpp:
     24        (WebCore::SecurityOrigin::createNonLocalWithAllowedFilePath):
     25        (WebCore::SecurityOrigin::canDisplay const):
     26        * page/SecurityOrigin.h:
     27
    1282019-04-23  Devin Rousso  <drousso@apple.com>
    229
  • trunk/Source/WebCore/dom/Document.cpp

    r244467 r244573  
    72267226void Document::applyQuickLookSandbox()
    72277227{
    7228     const URL& responseURL = m_frame->loader().activeDocumentLoader()->responseURL();
     7228    auto& documentLoader = *m_frame->loader().activeDocumentLoader();
     7229    auto documentURL = documentLoader.documentURL();
     7230    auto& responseURL = documentLoader.responseURL();
     7231    ASSERT(!documentURL.protocolIs(QLPreviewProtocol));
    72297232    ASSERT(responseURL.protocolIs(QLPreviewProtocol));
    72307233
    7231     auto securityOrigin = SecurityOrigin::create(responseURL);
     7234    auto securityOrigin = SecurityOrigin::createNonLocalWithAllowedFilePath(responseURL, documentURL.fileSystemPath());
    72327235    securityOrigin->setStorageBlockingPolicy(SecurityOrigin::BlockAllStorage);
    72337236    setSecurityOriginPolicy(SecurityOriginPolicy::create(WTFMove(securityOrigin)));
  • trunk/Source/WebCore/page/SecurityOrigin.cpp

    r242804 r244573  
    206206}
    207207
     208Ref<SecurityOrigin> SecurityOrigin::createNonLocalWithAllowedFilePath(const URL& url, const String& filePath)
     209{
     210    ASSERT(!url.isLocalFile());
     211    auto securityOrigin = SecurityOrigin::create(url);
     212    securityOrigin->m_filePath = filePath;
     213    return securityOrigin;
     214}
     215
    208216Ref<SecurityOrigin> SecurityOrigin::isolatedCopy() const
    209217{
     
    363371        return equalIgnoringASCIICase(m_data.protocol, protocol) || SecurityPolicy::isAccessToURLWhiteListed(this, url);
    364372
    365     if (SecurityPolicy::restrictAccessToLocal() && SchemeRegistry::shouldTreatURLSchemeAsLocal(protocol))
     373    if (!SecurityPolicy::restrictAccessToLocal())
     374        return true;
     375
     376    if (url.isLocalFile() && url.fileSystemPath() == m_filePath)
     377        return true;
     378
     379    if (SchemeRegistry::shouldTreatURLSchemeAsLocal(protocol))
    366380        return canLoadLocalResources() || SecurityPolicy::isAccessToURLWhiteListed(this, url);
    367381
  • trunk/Source/WebCore/page/SecurityOrigin.h

    r243163 r244573  
    5555    WEBCORE_EXPORT static Ref<SecurityOrigin> create(const String& protocol, const String& host, Optional<uint16_t> port);
    5656
     57    // QuickLook documents are in non-local origins even when loaded from file: URLs. They need to
     58    // be allowed to display their own file: URLs in order to perform reloads and same-document
     59    // navigations. This lets those documents specify the file path that should be allowed to be
     60    // displayed from their non-local origin.
     61    static Ref<SecurityOrigin> createNonLocalWithAllowedFilePath(const URL&, const String& filePath);
     62
    5763    // Some URL schemes use nested URLs for their security context. For example,
    5864    // filesystem URLs look like the following:
  • trunk/Tools/ChangeLog

    r244572 r244573  
     12019-04-23  Andy Estes  <aestes@apple.com>
     2
     3        [iOS] QuickLook documents loaded from file: URLs should be allowed to perform same-document navigations
     4        https://bugs.webkit.org/show_bug.cgi?id=196749
     5        <rdar://problem/35773454>
     6
     7        Reviewed by Daniel Bates.
     8
     9        Added a new QuickLook API test and added new expectations to existing QuickLook tests.
     10
     11        * TestWebKitAPI/Tests/WebKitCocoa/QuickLook.mm:
     12        (-[QuickLookDelegate webView:didStartProvisionalNavigation:]):
     13        (-[QuickLookDelegate webView:didFinishNavigation:]):
     14        (-[QuickLookDelegate _webView:didFailNavigation:withError:userInfo:]):
     15        (-[QuickLookDelegate webView:didFailProvisionalNavigation:withError:]):
     16        (runTest):
     17        (runTestDecideBeforeLoading):
     18        (runTestDecideAfterLoading):
     19        (TEST):
     20
    1212019-04-23  John Wilander  <wilander@apple.com>
    222
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/QuickLook.mm

    r243682 r244573  
    5858- (void)verifyDownload;
    5959
    60 @property (nonatomic) BOOL didStartQuickLookLoad;
    61 @property (nonatomic) BOOL didFinishQuickLookLoad;
     60@property (nonatomic, readonly) BOOL didFailNavigation;
     61@property (nonatomic, readonly) BOOL didFinishNavigation;
     62@property (nonatomic, readonly) BOOL didFinishQuickLookLoad;
     63@property (nonatomic, readonly) BOOL didStartQuickLookLoad;
    6264
    6365@end
     
    108110}
    109111
     112- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
     113{
     114    _didFailNavigation = NO;
     115    _didFinishNavigation = NO;
     116    _didFinishQuickLookLoad = NO;
     117    _didStartQuickLookLoad = NO;
     118}
     119
    110120- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
    111121{
     
    135145- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
    136146{
     147    EXPECT_FALSE(_didFailNavigation);
     148    EXPECT_FALSE(_didFinishNavigation);
     149    _didFinishNavigation = YES;
    137150    isDone = true;
    138151}
    139152
     153- (void)_webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error userInfo:(id<NSSecureCoding>)userInfo
     154{
     155    EXPECT_FALSE(_didFailNavigation);
     156    EXPECT_FALSE(_didFinishNavigation);
     157    _didFailNavigation = YES;
     158    isDone = true;
     159}
     160
    140161- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
    141162{
     163    EXPECT_FALSE(_didFailNavigation);
     164    EXPECT_FALSE(_didFinishNavigation);
     165    _didFailNavigation = YES;
    142166    isDone = true;
    143167}
     
    207231@end
    208232
    209 static void runTest(QuickLookDelegate *delegate, NSURLRequest *request, BOOL shouldDecidePolicyBeforeLoading)
     233static RetainPtr<WKWebView> runTest(QuickLookDelegate *delegate, NSURLRequest *request, BOOL shouldDecidePolicyBeforeLoading)
    210234{
    211235    auto processPool = adoptNS([[WKProcessPool alloc] init]);
     
    222246    isDone = false;
    223247    Util::run(&isDone);
    224 }
    225 
    226 static void runTestDecideBeforeLoading(QuickLookDelegate *delegate, NSURLRequest *request)
    227 {
    228     runTest(delegate, request, YES);
    229 }
    230 
    231 static void runTestDecideAfterLoading(QuickLookDelegate *delegate, NSURLRequest *request)
    232 {
    233     runTest(delegate, request, NO);
     248
     249    return webView;
     250}
     251
     252static RetainPtr<WKWebView> runTestDecideBeforeLoading(QuickLookDelegate *delegate, NSURLRequest *request)
     253{
     254    return runTest(delegate, request, YES);
     255}
     256
     257static RetainPtr<WKWebView> runTestDecideAfterLoading(QuickLookDelegate *delegate, NSURLRequest *request)
     258{
     259    return runTest(delegate, request, NO);
    234260}
    235261
     
    238264    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL responsePolicy:WKNavigationResponsePolicyAllow]);
    239265    runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
    240     EXPECT_TRUE([delegate didStartQuickLookLoad]);
    241     EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     266    EXPECT_FALSE([delegate didFailNavigation]);
     267    EXPECT_TRUE([delegate didFinishNavigation]);
     268    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     269    EXPECT_TRUE([delegate didStartQuickLookLoad]);
    242270}
    243271
     
    246274    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL previewMIMEType:pagesDocumentPreviewMIMEType responsePolicy:WKNavigationResponsePolicyAllow]);
    247275    runTestDecideAfterLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
    248     EXPECT_TRUE([delegate didStartQuickLookLoad]);
    249     EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     276    EXPECT_FALSE([delegate didFailNavigation]);
     277    EXPECT_TRUE([delegate didFinishNavigation]);
     278    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     279    EXPECT_TRUE([delegate didStartQuickLookLoad]);
    250280}
    251281
     
    271301    auto delegate = adoptNS([[QuickLookAsyncDelegate alloc] initWithExpectedFileURL:pagesDocumentURL responsePolicy:WKNavigationResponsePolicyAllow]);
    272302    runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
    273     EXPECT_TRUE([delegate didStartQuickLookLoad]);
    274     EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     303    EXPECT_FALSE([delegate didFailNavigation]);
     304    EXPECT_TRUE([delegate didFinishNavigation]);
     305    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     306    EXPECT_TRUE([delegate didStartQuickLookLoad]);
    275307}
    276308
     
    279311    auto delegate = adoptNS([[QuickLookAsyncDelegate alloc] initWithExpectedFileURL:pagesDocumentURL previewMIMEType:pagesDocumentPreviewMIMEType responsePolicy:WKNavigationResponsePolicyAllow]);
    280312    runTestDecideAfterLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
    281     EXPECT_TRUE([delegate didStartQuickLookLoad]);
    282     EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     313    EXPECT_FALSE([delegate didFailNavigation]);
     314    EXPECT_TRUE([delegate didFinishNavigation]);
     315    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     316    EXPECT_TRUE([delegate didStartQuickLookLoad]);
    283317}
    284318
     
    287321    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL responsePolicy:WKNavigationResponsePolicyCancel]);
    288322    runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
     323    EXPECT_FALSE([delegate didFinishNavigation]);
     324    EXPECT_FALSE([delegate didFinishQuickLookLoad]);
    289325    EXPECT_FALSE([delegate didStartQuickLookLoad]);
    290     EXPECT_FALSE([delegate didFinishQuickLookLoad]);
     326    EXPECT_TRUE([delegate didFailNavigation]);
    291327}
    292328
     
    295331    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL previewMIMEType:pagesDocumentPreviewMIMEType responsePolicy:WKNavigationResponsePolicyCancel]);
    296332    runTestDecideAfterLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
    297     EXPECT_TRUE([delegate didStartQuickLookLoad]);
    298     EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     333    EXPECT_FALSE([delegate didFinishNavigation]);
     334    EXPECT_TRUE([delegate didFailNavigation]);
     335    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     336    EXPECT_TRUE([delegate didStartQuickLookLoad]);
    299337}
    300338
     
    303341    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL responsePolicy:_WKNavigationResponsePolicyBecomeDownload]);
    304342    runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
     343    EXPECT_FALSE([delegate didFinishNavigation]);
     344    EXPECT_FALSE([delegate didFinishQuickLookLoad]);
    305345    EXPECT_FALSE([delegate didStartQuickLookLoad]);
    306     EXPECT_FALSE([delegate didFinishQuickLookLoad]);
     346    EXPECT_TRUE([delegate didFailNavigation]);
    307347
    308348    Util::run(&downloadIsDone);
     
    314354    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL previewMIMEType:pagesDocumentPreviewMIMEType responsePolicy:_WKNavigationResponsePolicyBecomeDownload]);
    315355    runTestDecideAfterLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
    316     EXPECT_TRUE([delegate didStartQuickLookLoad]);
    317     EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     356    EXPECT_FALSE([delegate didFinishNavigation]);
     357    EXPECT_TRUE([delegate didFailNavigation]);
     358    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     359    EXPECT_TRUE([delegate didStartQuickLookLoad]);
    318360}
    319361
     
    337379    auto delegate = adoptNS([[QuickLookPasswordDelegate alloc] initWithExpectedFileURL:passwordProtectedDocumentURL responsePolicy:WKNavigationResponsePolicyAllow]);
    338380    runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:passwordProtectedDocumentURL]);
     381    EXPECT_FALSE([delegate didFailNavigation]);
     382    EXPECT_FALSE([delegate didFinishNavigation]);
     383    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
    339384    EXPECT_TRUE([delegate didRequestPassword]);
     385    EXPECT_TRUE([delegate didStartQuickLookLoad]);
    340386}
    341387
     
    345391    auto delegate = adoptNS([[QuickLookPasswordDelegate alloc] initWithExpectedFileURL:passwordProtectedDocumentURL previewMIMEType:pagesDocumentPreviewMIMEType responsePolicy:WKNavigationResponsePolicyAllow]);
    346392    runTestDecideAfterLoading(delegate.get(), [NSURLRequest requestWithURL:passwordProtectedDocumentURL]);
     393    EXPECT_FALSE([delegate didFailNavigation]);
     394    EXPECT_FALSE([delegate didFinishNavigation]);
     395    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
    347396    EXPECT_TRUE([delegate didRequestPassword]);
     397    EXPECT_TRUE([delegate didStartQuickLookLoad]);
     398}
     399
     400TEST(QuickLook, ReloadAndSameDocumentNavigation)
     401{
     402    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL responsePolicy:WKNavigationResponsePolicyAllow]);
     403    auto webView = runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
     404    EXPECT_FALSE([delegate didFailNavigation]);
     405    EXPECT_TRUE([delegate didFinishNavigation]);
     406    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     407    EXPECT_TRUE([delegate didStartQuickLookLoad]);
     408
     409    isDone = false;
     410    [webView evaluateJavaScript:@"window.location.reload()" completionHandler:nil];
     411    Util::run(&isDone);
     412    EXPECT_FALSE([delegate didFailNavigation]);
     413    EXPECT_TRUE([delegate didFinishNavigation]);
     414    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
     415    EXPECT_TRUE([delegate didStartQuickLookLoad]);
     416
     417    isDone = false;
     418    [webView evaluateJavaScript:@"window.location = '#test'; window.location.hash" completionHandler:^(id _Nullable value, NSError * _Nullable error) {
     419        EXPECT_NULL(error);
     420        EXPECT_WK_STREQ(@"#test", value);
     421        isDone = true;
     422    }];
     423    Util::run(&isDone);
    348424}
    349425
Note: See TracChangeset for help on using the changeset viewer.