[iOS] WebKit should consult the navigation response policy delegate before previewing...
authoraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 31 Mar 2019 17:37:45 +0000 (17:37 +0000)
committeraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 31 Mar 2019 17:37:45 +0000 (17:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196433
<rdar://problem/49293305>

Reviewed by Tim Horton.

Source/WebCore:

When ResourceLoader would encounter a response with a MIME type that QuickLook supports, the
response would be implicitly allowed and a QuickLook preview would be generated. After
generating, the client's navigation response policy delegate would be notified of the
preview response, but not the underlying response. Notably, the preview response has a URL
scheme of "x-apple-ql-id", does not include any underlying HTTP headers, and usually has a
MIME type of "text/html" or "application/pdf" rather than the underlying response MIME type.

To allow clients to make better navigation response policy decisions, this patch changes the
above behavior for WKWebView clients that have linked against a version of WebKit that
includes this change. Rather than notifying the client's navigation response policy delegate
of the preview response, we notify the client of the underlying response. Only if the client
responds with a policy of "allow" will the QuickLook preview response be loaded (without
another call to the navigation response policy delegate).

Non-WKWebView clients and clients that have linked against a version of WebKit that does not
include this change will retain the original behavior.

Covered by existing layout tests and new and existing API tests.

* WebCore.xcodeproj/project.pbxproj:
* loader/SubresourceLoader.cpp:
(WebCore::SubresourceLoader::shouldCreatePreviewLoaderForResponse const):
(WebCore::SubresourceLoader::didReceiveResponse):
* loader/ios/PreviewLoader.h:
* loader/ios/PreviewLoader.mm:
(-[WebPreviewLoader initWithResourceLoader:resourceResponse:]):
(-[WebPreviewLoader _loadPreviewIfNeeded]):
(-[WebPreviewLoader connection:didReceiveData:lengthReceived:]):
(-[WebPreviewLoader connectionDidFinishLoading:]):
(-[WebPreviewLoader connection:didFailWithError:]):
(WebCore::PreviewLoader::create):
(WebCore::PreviewLoader::didReceiveResponse):
(-[WebPreviewLoader _sendDidReceiveResponseIfNecessary]): Deleted.
(WebCore::PreviewLoader::shouldCreateForMIMEType): Deleted.
* page/Settings.yaml:
* platform/MIMETypeRegistry.cpp:
(WebCore::MIMETypeRegistry::canShowMIMEType):
* platform/network/ios/PreviewConverter.h:
* platform/network/ios/PreviewConverter.mm:
(WebCore::PreviewConverter::supportsMIMEType):

Source/WebKit:

Added WKWebViewConfiguration SPI for setting the QuickLook navigation response policy
decision behavior. The configuration setting defaults to YES for clients linked on or after
this WebKit change and NO otherwise.

* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions):
* Shared/WebPreferences.yaml:
* Shared/ios/QuickLookDocumentData.cpp:
(WebKit::QuickLookDocumentData::isEmpty const):
* Shared/ios/QuickLookDocumentData.h:
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _initializeWithConfiguration:]):
* UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
(defaultShouldDecidePolicyBeforeLoadingQuickLookPreview):
(-[WKWebViewConfiguration init]):
(-[WKWebViewConfiguration encodeWithCoder:]):
(-[WKWebViewConfiguration initWithCoder:]):
(-[WKWebViewConfiguration copyWithZone:]):
(-[WKWebViewConfiguration _shouldDecidePolicyBeforeLoadingQuickLookPreview]):
(-[WKWebViewConfiguration _setShouldDecidePolicyBeforeLoadingQuickLookPreview:]):
* UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
* UIProcess/Cocoa/VersionChecks.h:
* WebProcess/WebCoreSupport/ios/WebPreviewLoaderClient.cpp:
(WebKit::WebPreviewLoaderClient::didReceiveDataArray):

Source/WTF:

* wtf/NeverDestroyed.h:
(WTF::NeverDestroyed::operator->):
(WTF::NeverDestroyed::operator-> const):

Tools:

Enhanced API test coverage to include all navigation response policy decisions in both
linked-before and linked-on-or-after modes. Also added new expectations for all tests.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebCore/ios/PreviewConverter.cpp: Renamed from Tools/TestWebKitAPI/Tests/WebCore/ios/PreviewLoader.cpp.
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKitCocoa/QuickLook.mm:
(readFile):
(-[QuickLookDelegate initWithExpectedFileURL:responsePolicy:]):
(-[QuickLookDelegate initWithExpectedFileURL:previewMIMEType:responsePolicy:]):
(-[QuickLookDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
(-[QuickLookDelegate _webView:didStartLoadForQuickLookDocumentInMainFrameWithFileName:uti:]):
(-[QuickLookDelegate _webView:didFinishLoadForQuickLookDocumentInMainFrame:]):
(-[QuickLookDelegate webView:didFailProvisionalNavigation:withError:]):
(-[QuickLookDelegate _webViewWebProcessDidCrash:]):
(-[QuickLookDelegate _downloadDidStart:]):
(-[QuickLookDelegate _download:didReceiveResponse:]):
(-[QuickLookDelegate _download:didReceiveData:]):
(-[QuickLookDelegate _download:decideDestinationWithSuggestedFilename:completionHandler:]):
(-[QuickLookDelegate _downloadDidFinish:]):
(-[QuickLookDelegate _download:didFailWithError:]):
(-[QuickLookDelegate _downloadDidCancel:]):
(-[QuickLookDelegate verifyDownload]):
(runTest):
(runTestDecideBeforeLoading):
(runTestDecideAfterLoading):
(TEST):
(-[QuickLookAsyncDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
(-[QuickLookPasswordDelegate _webViewDidRequestPasswordForQuickLookDocument:]):
(-[QuickLookFrameLoadDelegate webView:didFinishLoadForFrame:]):
(-[QuickLookNavigationDelegate _webView:didStartLoadForQuickLookDocumentInMainFrameWithFileName:uti:]): Deleted.
(-[QuickLookNavigationDelegate _webView:didFinishLoadForQuickLookDocumentInMainFrame:]): Deleted.
(-[QuickLookNavigationDelegate webView:didFinishNavigation:]): Deleted.
(-[QuickLookAsyncNavigationDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]): Deleted.
(-[QuickLookAsyncNavigationDelegate _webView:didStartLoadForQuickLookDocumentInMainFrameWithFileName:uti:]): Deleted.
(-[QuickLookAsyncNavigationDelegate _webView:didFinishLoadForQuickLookDocumentInMainFrame:]): Deleted.
(-[QuickLookAsyncNavigationDelegate webView:didFinishNavigation:]): Deleted.
(-[QuickLookDecidePolicyDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]): Deleted.
(-[QuickLookDecidePolicyDelegate webView:didFailProvisionalNavigation:withError:]): Deleted.
(-[QuickLookDecidePolicyDelegate _webViewWebProcessDidCrash:]): Deleted.
(-[QuickLookPasswordNavigationDelegate _webViewDidRequestPasswordForQuickLookDocument:]): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243682 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
Source/WTF/ChangeLog
Source/WTF/wtf/NeverDestroyed.h
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/loader/SubresourceLoader.cpp
Source/WebCore/loader/ios/PreviewLoader.h
Source/WebCore/loader/ios/PreviewLoader.mm
Source/WebCore/page/Settings.yaml
Source/WebCore/platform/MIMETypeRegistry.cpp
Source/WebCore/platform/network/ios/PreviewConverter.h
Source/WebCore/platform/network/ios/PreviewConverter.mm
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
Source/WebKit/Shared/WebPreferences.yaml
Source/WebKit/Shared/ios/QuickLookDocumentData.cpp
Source/WebKit/Shared/ios/QuickLookDocumentData.h
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h
Source/WebKit/UIProcess/Cocoa/VersionChecks.h
Source/WebKit/WebProcess/WebCoreSupport/ios/WebPreviewLoaderClient.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebCore/ios/PreviewConverter.cpp [moved from Tools/TestWebKitAPI/Tests/WebCore/ios/PreviewLoader.cpp with 76% similarity]
Tools/TestWebKitAPI/Tests/WebKitCocoa/QuickLook.mm

index d1ef35f..f4b33b0 100644 (file)
@@ -1,3 +1,15 @@
+2019-03-31  Andy Estes  <aestes@apple.com>
+
+        [iOS] WebKit should consult the navigation response policy delegate before previewing a QuickLook document
+        https://bugs.webkit.org/show_bug.cgi?id=196433
+        <rdar://problem/49293305>
+
+        Reviewed by Tim Horton.
+
+        * wtf/NeverDestroyed.h:
+        (WTF::NeverDestroyed::operator->):
+        (WTF::NeverDestroyed::operator-> const):
+
 2019-03-28  Fujii Hironori  <Hironori.Fujii@sony.com>
 
         Unreviewed build fix.
index e7e8a7e..e0e4677 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -60,9 +60,13 @@ public:
     operator T&() { return *storagePointer(); }
     T& get() { return *storagePointer(); }
 
+    T* operator->() { return storagePointer(); }
+
     operator const T&() const { return *storagePointer(); }
     const T& get() const { return *storagePointer(); }
 
+    const T* operator->() const { return storagePointer(); }
+
 private:
     using PointerType = typename std::remove_const<T>::type*;
 
index b54de56..6c4c628 100644 (file)
@@ -1,3 +1,52 @@
+2019-03-31  Andy Estes  <aestes@apple.com>
+
+        [iOS] WebKit should consult the navigation response policy delegate before previewing a QuickLook document
+        https://bugs.webkit.org/show_bug.cgi?id=196433
+        <rdar://problem/49293305>
+
+        Reviewed by Tim Horton.
+
+        When ResourceLoader would encounter a response with a MIME type that QuickLook supports, the
+        response would be implicitly allowed and a QuickLook preview would be generated. After
+        generating, the client's navigation response policy delegate would be notified of the
+        preview response, but not the underlying response. Notably, the preview response has a URL
+        scheme of "x-apple-ql-id", does not include any underlying HTTP headers, and usually has a
+        MIME type of "text/html" or "application/pdf" rather than the underlying response MIME type.
+
+        To allow clients to make better navigation response policy decisions, this patch changes the
+        above behavior for WKWebView clients that have linked against a version of WebKit that
+        includes this change. Rather than notifying the client's navigation response policy delegate
+        of the preview response, we notify the client of the underlying response. Only if the client
+        responds with a policy of "allow" will the QuickLook preview response be loaded (without
+        another call to the navigation response policy delegate).
+
+        Non-WKWebView clients and clients that have linked against a version of WebKit that does not
+        include this change will retain the original behavior.
+
+        Covered by existing layout tests and new and existing API tests.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * loader/SubresourceLoader.cpp:
+        (WebCore::SubresourceLoader::shouldCreatePreviewLoaderForResponse const):
+        (WebCore::SubresourceLoader::didReceiveResponse):
+        * loader/ios/PreviewLoader.h:
+        * loader/ios/PreviewLoader.mm:
+        (-[WebPreviewLoader initWithResourceLoader:resourceResponse:]):
+        (-[WebPreviewLoader _loadPreviewIfNeeded]):
+        (-[WebPreviewLoader connection:didReceiveData:lengthReceived:]):
+        (-[WebPreviewLoader connectionDidFinishLoading:]):
+        (-[WebPreviewLoader connection:didFailWithError:]):
+        (WebCore::PreviewLoader::create):
+        (WebCore::PreviewLoader::didReceiveResponse):
+        (-[WebPreviewLoader _sendDidReceiveResponseIfNecessary]): Deleted.
+        (WebCore::PreviewLoader::shouldCreateForMIMEType): Deleted.
+        * page/Settings.yaml:
+        * platform/MIMETypeRegistry.cpp:
+        (WebCore::MIMETypeRegistry::canShowMIMEType):
+        * platform/network/ios/PreviewConverter.h:
+        * platform/network/ios/PreviewConverter.mm:
+        (WebCore::PreviewConverter::supportsMIMEType):
+
 2019-03-29  Dean Jackson  <dino@apple.com>
 
         gl.readPixels with type gl.FLOAT does not work
index c142980..d4017d5 100644 (file)
                A1BB85B92159B3AE0067E07D /* JSMockPaymentError.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB85B52159B38A0067E07D /* JSMockPaymentError.h */; };
                A1BF6B821AA96C7D00AF4A8A /* MockContentFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1BF6B801AA96C7D00AF4A8A /* MockContentFilter.cpp */; };
                A1BF6B831AA96C7D00AF4A8A /* MockContentFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BF6B811AA96C7D00AF4A8A /* MockContentFilter.h */; };
-               A1C1507A1E3F2B3E0032C98C /* PreviewConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = A1C150781E3F2B3E0032C98C /* PreviewConverter.h */; };
+               A1C1507A1E3F2B3E0032C98C /* PreviewConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = A1C150781E3F2B3E0032C98C /* PreviewConverter.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A1CBEF641F9F11290028DE7C /* MockPaymentMethod.h in Headers */ = {isa = PBXBuildFile; fileRef = A1CBEF631F9F11290028DE7C /* MockPaymentMethod.h */; };
                A1CC56671F46147A00A4555B /* JSPaymentAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = A1CC56651F46146800A4555B /* JSPaymentAddress.h */; };
                A1CC56691F46148000A4555B /* JSPaymentComplete.h in Headers */ = {isa = PBXBuildFile; fileRef = A1CC564E1F46145200A4555B /* JSPaymentComplete.h */; };
index 483ecd3..23de154 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -63,6 +63,7 @@
 #endif
 
 #if USE(QUICK_LOOK)
+#include "PreviewConverter.h"
 #include "PreviewLoader.h"
 #endif
 
@@ -304,7 +305,7 @@ bool SubresourceLoader::shouldCreatePreviewLoaderForResponse(const ResourceRespo
     if (m_previewLoader)
         return false;
 
-    return PreviewLoader::shouldCreateForMIMEType(response.mimeType());
+    return PreviewConverter::supportsMIMEType(response.mimeType());
 }
 
 #endif
@@ -319,7 +320,8 @@ void SubresourceLoader::didReceiveResponse(const ResourceResponse& response, Com
 #if USE(QUICK_LOOK)
     if (shouldCreatePreviewLoaderForResponse(response)) {
         m_previewLoader = PreviewLoader::create(*this, response);
-        return;
+        if (m_previewLoader->didReceiveResponse(response))
+            return;
     }
 #endif
 #if ENABLE(SERVICE_WORKER)
index a630974..618e942 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2009-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -41,10 +41,10 @@ class SharedBuffer;
 class PreviewLoader {
     WTF_MAKE_NONCOPYABLE(PreviewLoader);
 public:
-    WEBCORE_EXPORT static bool shouldCreateForMIMEType(const String&);
     static std::unique_ptr<PreviewLoader> create(ResourceLoader&, const ResourceResponse&);
     ~PreviewLoader();
 
+    bool didReceiveResponse(const ResourceResponse&);
     bool didReceiveData(const char* data, unsigned length);
     bool didReceiveBuffer(const SharedBuffer&);
     bool didFinishLoading();
index 7251d70..f6b8221 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2009-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +29,7 @@
 #if USE(QUICK_LOOK)
 
 #import "DocumentLoader.h"
+#import "Frame.h"
 #import "FrameLoader.h"
 #import "FrameLoaderClient.h"
 #import "Logging.h"
@@ -36,6 +37,7 @@
 #import "PreviewLoaderClient.h"
 #import "QuickLook.h"
 #import "ResourceLoader.h"
+#import "Settings.h"
 #import <pal/spi/ios/QuickLookSPI.h>
 #import <wtf/NeverDestroyed.h>
 
@@ -47,7 +49,7 @@ using namespace WebCore;
     RefPtr<PreviewLoaderClient> _client;
     std::unique_ptr<PreviewConverter> _converter;
     RetainPtr<NSMutableArray> _bufferedDataArray;
-    BOOL _hasSentDidReceiveResponse;
+    BOOL _hasLoadedPreview;
     BOOL _hasProcessedResponse;
     RefPtr<SharedBuffer> _bufferedData;
     long long _lengthReceived;
@@ -59,6 +61,8 @@ using namespace WebCore;
 - (void)finishedAppending;
 - (void)failed;
 
+@property (nonatomic, readonly) BOOL shouldDecidePolicyBeforeLoading;
+
 @end
 
 @implementation WebPreviewLoader
@@ -77,14 +81,14 @@ static PreviewLoaderClient& emptyClient()
 
 - (instancetype)initWithResourceLoader:(ResourceLoader&)resourceLoader resourceResponse:(const ResourceResponse&)resourceResponse
 {
-    self = [super init];
-    if (!self)
+    if (!(self = [super init]))
         return nil;
 
     _resourceLoader = makeWeakPtr(resourceLoader);
     _response = resourceResponse;
     _converter = std::make_unique<PreviewConverter>(self, _response);
     _bufferedDataArray = adoptNS([[NSMutableArray alloc] init]);
+    _shouldDecidePolicyBeforeLoading = resourceLoader.frame()->settings().shouldDecidePolicyBeforeLoadingQuickLookPreview();
 
     if (testingClient())
         _client = testingClient();
@@ -119,15 +123,16 @@ static PreviewLoaderClient& emptyClient()
     _client->didFail();
 }
 
-- (void)_sendDidReceiveResponseIfNecessary
+- (void)_loadPreviewIfNeeded
 {
     if (!_resourceLoader)
         return;
 
     ASSERT(!_resourceLoader->reachedTerminalState());
-    if (_hasSentDidReceiveResponse)
+    if (_hasLoadedPreview)
         return;
 
+    _hasLoadedPreview = YES;
     [_bufferedDataArray removeAllObjects];
 
     ResourceResponse response { _converter->previewResponse() };
@@ -136,7 +141,12 @@ static PreviewLoaderClient& emptyClient()
 
     _resourceLoader->documentLoader()->setPreviewConverter(WTFMove(_converter));
 
-    _hasSentDidReceiveResponse = YES;
+    if (_shouldDecidePolicyBeforeLoading) {
+        _hasProcessedResponse = YES;
+        _resourceLoader->documentLoader()->setResponse(response);
+        return;
+    }
+
     _hasProcessedResponse = NO;
     _resourceLoader->didReceiveResponse(response, [self, retainedSelf = retainPtr(self)] {
         _hasProcessedResponse = YES;
@@ -170,8 +180,8 @@ static PreviewLoaderClient& emptyClient()
     ASSERT_UNUSED(connection, !connection);
     if (_resourceLoader->reachedTerminalState())
         return;
-    
-    [self _sendDidReceiveResponseIfNecessary];
+
+    [self _loadPreviewIfNeeded];
 
     auto dataLength = data.length;
 
@@ -201,7 +211,7 @@ static PreviewLoaderClient& emptyClient()
     if (_resourceLoader->reachedTerminalState())
         return;
     
-    ASSERT(_hasSentDidReceiveResponse);
+    ASSERT(_hasLoadedPreview);
 
     if (!_hasProcessedResponse) {
         _needsToCallDidFinishLoading = YES;
@@ -226,7 +236,6 @@ static inline bool isQuickLookPasswordError(NSError *error)
         return;
 
     if (!isQuickLookPasswordError(error)) {
-        [self _sendDidReceiveResponseIfNecessary];
         _resourceLoader->didFail(error);
         return;
     }
@@ -256,28 +265,15 @@ PreviewLoader::~PreviewLoader()
 {
 }
 
-bool PreviewLoader::shouldCreateForMIMEType(const String& mimeType)
+std::unique_ptr<PreviewLoader> PreviewLoader::create(ResourceLoader& loader, const ResourceResponse& response)
 {
-    if (equalLettersIgnoringASCIICase(mimeType, "text/html") || equalLettersIgnoringASCIICase(mimeType, "text/plain"))
-        return false;
-
-    static std::once_flag onceFlag;
-    static NeverDestroyed<HashSet<String, ASCIICaseInsensitiveHash>> supportedMIMETypes;
-    std::call_once(onceFlag, [] {
-        for (NSString *mimeType in QLPreviewGetSupportedMIMETypesSet())
-            supportedMIMETypes.get().add(mimeType);
-    });
-
-    if (mimeType.isNull())
-        return false;
-
-    return supportedMIMETypes.get().contains(mimeType);
+    ASSERT(PreviewConverter::supportsMIMEType(response.mimeType()));
+    return std::make_unique<PreviewLoader>(loader, response);
 }
 
-std::unique_ptr<PreviewLoader> PreviewLoader::create(ResourceLoader& loader, const ResourceResponse& response)
+bool PreviewLoader::didReceiveResponse(const ResourceResponse&)
 {
-    ASSERT(shouldCreateForMIMEType(response.mimeType()));
-    return std::make_unique<PreviewLoader>(loader, response);
+    return ![m_previewLoader shouldDecidePolicyBeforeLoading];
 }
 
 bool PreviewLoader::didReceiveData(const char* data, unsigned length)
index bd6828d..d45338d 100644 (file)
@@ -827,6 +827,9 @@ adClickAttributionEnabled:
 blockingOfSmallPluginsEnabled:
   initial: true
 
+shouldDecidePolicyBeforeLoadingQuickLookPreview:
+  initial: false
+
 # Deprecated
 
 iceCandidateFilteringEnabled:
index f9eabb5..6cae14a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2019 Apple Inc. All rights reserved.
  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
  *
  * Redistribution and use in source and binary forms, with or without
 #include "ImageDecoderAVFObjC.h"
 #endif
 
+#if USE(QUICK_LOOK)
+#include "PreviewConverter.h"
+#endif
+
 namespace WebCore {
 
 const HashSet<String, ASCIICaseInsensitiveHash>& MIMETypeRegistry::supportedImageMIMETypes()
@@ -643,6 +647,11 @@ bool MIMETypeRegistry::canShowMIMEType(const String& mimeType)
     if (isSupportedJavaScriptMIMEType(mimeType) || isSupportedJSONMIMEType(mimeType))
         return true;
 
+#if USE(QUICK_LOOK)
+    if (PreviewConverter::supportsMIMEType(mimeType))
+        return true;
+#endif
+
     if (startsWithLettersIgnoringASCIICase(mimeType, "text/"))
         return !isUnsupportedTextMIMEType(mimeType);
 
index 01c7d25..5a06f2e 100644 (file)
@@ -41,6 +41,8 @@ public:
     PreviewConverter(id delegate, const ResourceResponse&, const String& password = { });
     PreviewConverter(NSData *, const String& uti, const String& password = { });
 
+    WEBCORE_EXPORT static bool supportsMIMEType(const String& mimeType);
+
     QLPreviewConverter *platformConverter() const { return m_platformConverter.get(); }
     ResourceRequest safeRequest(const ResourceRequest&) const;
     ResourceRequest previewRequest() const;
index 482aaab..b5cd283 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
 
 #if USE(QUICK_LOOK)
 
+#import "QuickLook.h"
 #import "ResourceRequest.h"
 #import "ResourceResponse.h"
 #import <pal/ios/QuickLookSoftLink.h>
@@ -53,6 +54,24 @@ PreviewConverter::PreviewConverter(NSData *data, const String& uti, const String
 {
 }
 
+bool PreviewConverter::supportsMIMEType(const String& mimeType)
+{
+    if (equalLettersIgnoringASCIICase(mimeType, "text/html") || equalLettersIgnoringASCIICase(mimeType, "text/plain"))
+        return false;
+
+    static std::once_flag onceFlag;
+    static NeverDestroyed<HashSet<String, ASCIICaseInsensitiveHash>> supportedMIMETypes;
+    std::call_once(onceFlag, [] {
+        for (NSString *mimeType in QLPreviewGetSupportedMIMETypesSet())
+            supportedMIMETypes->add(mimeType);
+    });
+
+    if (mimeType.isNull())
+        return false;
+
+    return supportedMIMETypes->contains(mimeType);
+}
+
 ResourceRequest PreviewConverter::safeRequest(const ResourceRequest& request) const
 {
     return [m_platformConverter safeRequestForRequest:request.nsURLRequest(HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody)];
index 1ffd48c..86f091d 100644 (file)
@@ -1,3 +1,36 @@
+2019-03-31  Andy Estes  <aestes@apple.com>
+
+        [iOS] WebKit should consult the navigation response policy delegate before previewing a QuickLook document
+        https://bugs.webkit.org/show_bug.cgi?id=196433
+        <rdar://problem/49293305>
+
+        Reviewed by Tim Horton.
+
+        Added WKWebViewConfiguration SPI for setting the QuickLook navigation response policy
+        decision behavior. The configuration setting defaults to YES for clients linked on or after
+        this WebKit change and NO otherwise.
+
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions):
+        * Shared/WebPreferences.yaml:
+        * Shared/ios/QuickLookDocumentData.cpp:
+        (WebKit::QuickLookDocumentData::isEmpty const):
+        * Shared/ios/QuickLookDocumentData.h:
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _initializeWithConfiguration:]):
+        * UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
+        (defaultShouldDecidePolicyBeforeLoadingQuickLookPreview):
+        (-[WKWebViewConfiguration init]):
+        (-[WKWebViewConfiguration encodeWithCoder:]):
+        (-[WKWebViewConfiguration initWithCoder:]):
+        (-[WKWebViewConfiguration copyWithZone:]):
+        (-[WKWebViewConfiguration _shouldDecidePolicyBeforeLoadingQuickLookPreview]):
+        (-[WKWebViewConfiguration _setShouldDecidePolicyBeforeLoadingQuickLookPreview:]):
+        * UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
+        * UIProcess/Cocoa/VersionChecks.h:
+        * WebProcess/WebCoreSupport/ios/WebPreviewLoaderClient.cpp:
+        (WebKit::WebPreviewLoaderClient::didReceiveDataArray):
+
 2019-03-30  Zalan Bujtas  <zalan@apple.com>
 
         [ContentChangeObserver] Subframe load should not reset content observation on the mainframe
index cfa99b1..f8e4642 100644 (file)
@@ -55,7 +55,7 @@
 #include <wtf/RunLoop.h>
 
 #if USE(QUICK_LOOK)
-#include <WebCore/PreviewLoader.h>
+#include <WebCore/PreviewConverter.h>
 #endif
 
 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkResourceLoader::" fmt, this, ##__VA_ARGS__)
@@ -386,7 +386,7 @@ bool NetworkResourceLoader::shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptio
     ASSERT(isMainResource());
 
 #if USE(QUICK_LOOK)
-    if (PreviewLoader::shouldCreateForMIMEType(response.mimeType()))
+    if (PreviewConverter::supportsMIMEType(response.mimeType()))
         return false;
 #endif
 
index 7dcd589..9f0f1ac 100644 (file)
@@ -1192,6 +1192,10 @@ EditableImagesEnabled:
   type: bool
   defaultValue: false
 
+ShouldDecidePolicyBeforeLoadingQuickLookPreview:
+  defaultValue: false
+  type: bool
+
 # For experimental features:
 # The type should be boolean.
 # You must provide a humanReadableName and humanReadableDescription for all experimental features. They
index 0f85919..8bbda59 100644 (file)
@@ -46,6 +46,11 @@ CFDataRef QuickLookDocumentData::decodedData() const
     return m_data[0].get();
 }
 
+bool QuickLookDocumentData::isEmpty() const
+{
+    return m_data.isEmpty();
+}
+
 void QuickLookDocumentData::clear()
 {
     m_data.clear();
index 1f255b5..7016f41 100644 (file)
@@ -40,6 +40,7 @@ class QuickLookDocumentData {
 public:
     void append(CFDataRef);
     CFDataRef decodedData() const;
+    bool isEmpty() const;
     void clear();
     void encode(IPC::Encoder&) const;
     static bool decode(IPC::Decoder&, QuickLookDocumentData&);
index ec6cc7f..d8e9436 100644 (file)
@@ -626,6 +626,7 @@ static void validate(WKWebViewConfiguration *configuration)
     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::userInterfaceDirectionPolicyKey(), WebKit::WebPreferencesStore::Value(static_cast<uint32_t>(WebCore::UserInterfaceDirectionPolicy::Content)));
     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::systemLayoutDirectionKey(), WebKit::WebPreferencesStore::Value(static_cast<uint32_t>(WebCore::TextDirection::LTR)));
     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowSettingAnyXHRHeaderFromFileURLsKey(), WebKit::WebPreferencesStore::Value(shouldAllowSettingAnyXHRHeaderFromFileURLs()));
+    pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::shouldDecidePolicyBeforeLoadingQuickLookPreviewKey(), WebKit::WebPreferencesStore::Value(!![_configuration _shouldDecidePolicyBeforeLoadingQuickLookPreview]));
 #if USE(SYSTEM_PREVIEW)
     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::systemPreviewEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _systemPreviewEnabled]));
 #endif
index 77b19dd..d602aaf 100644 (file)
@@ -99,6 +99,16 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     return _WKDragLiftDelayShort;
 }
 
+static bool defaultShouldDecidePolicyBeforeLoadingQuickLookPreview()
+{
+#if USE(QUICK_LOOK)
+    static bool shouldDecide = linkedOnOrAfter(WebKit::SDKVersion::FirstThatDecidesPolicyBeforeLoadingQuickLookPreview);
+    return shouldDecide;
+#else
+    return false;
+#endif
+}
+
 #endif
 
 @implementation WKWebViewConfiguration {
@@ -129,6 +139,7 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     BOOL _textInteractionGesturesEnabled;
     BOOL _longPressActionsEnabled;
     BOOL _systemPreviewEnabled;
+    BOOL _shouldDecidePolicyBeforeLoadingQuickLookPreview;
 #endif
 
     BOOL _invisibleAutoplayNotPermitted;
@@ -236,6 +247,7 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     _longPressActionsEnabled = YES;
 #endif
     _systemPreviewEnabled = NO;
+    _shouldDecidePolicyBeforeLoadingQuickLookPreview = defaultShouldDecidePolicyBeforeLoadingQuickLookPreview();
 #endif // PLATFORM(IOS_FAMILY)
 
     _mediaContentTypesRequiringHardwareSupport = WebCore::Settings::defaultMediaContentTypesRequiringHardwareSupport();
@@ -291,6 +303,7 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     [coder encodeBool:self._textInteractionGesturesEnabled forKey:@"textInteractionGesturesEnabled"];
     [coder encodeBool:self._longPressActionsEnabled forKey:@"longPressActionsEnabled"];
     [coder encodeBool:self._systemPreviewEnabled forKey:@"systemPreviewEnabled"];
+    [coder encodeBool:self._shouldDecidePolicyBeforeLoadingQuickLookPreview forKey:@"shouldDecidePolicyBeforeLoadingQuickLookPreview"];
 #else
     [coder encodeInteger:self.userInterfaceDirectionPolicy forKey:@"userInterfaceDirectionPolicy"];
 #endif
@@ -325,6 +338,7 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     self._textInteractionGesturesEnabled = [coder decodeBoolForKey:@"textInteractionGesturesEnabled"];
     self._longPressActionsEnabled = [coder decodeBoolForKey:@"longPressActionsEnabled"];
     self._systemPreviewEnabled = [coder decodeBoolForKey:@"systemPreviewEnabled"];
+    self._shouldDecidePolicyBeforeLoadingQuickLookPreview = [coder decodeBoolForKey:@"shouldDecidePolicyBeforeLoadingQuickLookPreview"];
 #else
     auto userInterfaceDirectionPolicyCandidate = static_cast<WKUserInterfaceDirectionPolicy>([coder decodeIntegerForKey:@"userInterfaceDirectionPolicy"]);
     if (userInterfaceDirectionPolicyCandidate == WKUserInterfaceDirectionPolicyContent || userInterfaceDirectionPolicyCandidate == WKUserInterfaceDirectionPolicySystem)
@@ -381,6 +395,7 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     configuration->_textInteractionGesturesEnabled = self->_textInteractionGesturesEnabled;
     configuration->_longPressActionsEnabled = self->_longPressActionsEnabled;
     configuration->_systemPreviewEnabled = self->_systemPreviewEnabled;
+    configuration->_shouldDecidePolicyBeforeLoadingQuickLookPreview = self->_shouldDecidePolicyBeforeLoadingQuickLookPreview;
 #endif
 #if PLATFORM(MAC)
     configuration->_userInterfaceDirectionPolicy = self->_userInterfaceDirectionPolicy;
@@ -732,6 +747,16 @@ ALLOW_DEPRECATED_DECLARATIONS_END
     _systemPreviewEnabled = enabled;
 }
 
+- (BOOL)_shouldDecidePolicyBeforeLoadingQuickLookPreview
+{
+    return _shouldDecidePolicyBeforeLoadingQuickLookPreview;
+}
+
+- (void)_setShouldDecidePolicyBeforeLoadingQuickLookPreview:(BOOL)shouldDecide
+{
+    _shouldDecidePolicyBeforeLoadingQuickLookPreview = shouldDecide;
+}
+
 #endif // PLATFORM(IOS_FAMILY)
 
 - (BOOL)_invisibleAutoplayNotPermitted
index 8c16e39..78027fd 100644 (file)
@@ -82,6 +82,7 @@ typedef NS_ENUM(NSUInteger, _WKDragLiftDelay) {
 @property (nonatomic, setter=_setTextInteractionGesturesEnabled:) BOOL _textInteractionGesturesEnabled WK_API_AVAILABLE(ios(12.0));
 @property (nonatomic, setter=_setLongPressActionsEnabled:) BOOL _longPressActionsEnabled WK_API_AVAILABLE(ios(12.0));
 @property (nonatomic, setter=_setSystemPreviewEnabled:) BOOL _systemPreviewEnabled WK_API_AVAILABLE(ios(12.0));
+@property (nonatomic, setter=_setShouldDecidePolicyBeforeLoadingQuickLookPreview:) BOOL _shouldDecidePolicyBeforeLoadingQuickLookPreview WK_API_AVAILABLE(ios(WK_IOS_TBA));
 #else
 @property (nonatomic, setter=_setShowsURLsInToolTips:) BOOL _showsURLsInToolTips WK_API_AVAILABLE(macos(10.12));
 @property (nonatomic, setter=_setServiceControlsEnabled:) BOOL _serviceControlsEnabled WK_API_AVAILABLE(macos(10.12));
index 3b350be..f4d4281 100644 (file)
@@ -34,6 +34,7 @@
 #define DYLD_IOS_VERSION_FIRST_WITH_PROCESS_SWAP_ON_CROSS_SITE_NAVIGATION 0
 #define DYLD_IOS_VERSION_FIRST_WITH_SNAPSHOT_AFTER_SCREEN_UPDATES 0
 #define DYLD_IOS_VERSION_FIRST_WHERE_DOWNLOAD_ATTRIBUTE_DOES_NOT_OVERRIDE_NAVIGATION_DELEGATE 0
+#define DYLD_IOS_VERSION_FIRST_THAT_DECIDES_POLICY_BEFORE_LOADING_QUICK_LOOK_PREVIEW 0
 #define DYLD_MACOS_VERSION_FIRST_WITH_SNAPSHOT_AFTER_SCREEN_UPDATES 0
 #define DYLD_MACOS_VERSION_FIRST_WHERE_DOWNLOAD_ATTRIBUTE_DOES_NOT_OVERRIDE_NAVIGATION_DELEGATE 0
 #endif
@@ -61,6 +62,7 @@ enum class SDKVersion : uint32_t {
     FirstWithSnapshotAfterScreenUpdates = DYLD_IOS_VERSION_FIRST_WITH_SNAPSHOT_AFTER_SCREEN_UPDATES,
     FirstWhereDownloadAttributeDoesNotOverrideNavigationDelegate = DYLD_IOS_VERSION_FIRST_WHERE_DOWNLOAD_ATTRIBUTE_DOES_NOT_OVERRIDE_NAVIGATION_DELEGATE,
     FirstWithDeviceOrientationAndMotionPermissionAPI = DYLD_IOS_VERSION_FIRST_WITH_DEVICE_ORIENTATION_AND_MOTION_PERMISSION_API,
+    FirstThatDecidesPolicyBeforeLoadingQuickLookPreview = DYLD_IOS_VERSION_FIRST_THAT_DECIDES_POLICY_BEFORE_LOADING_QUICK_LOOK_PREVIEW,
 #elif PLATFORM(MAC)
     FirstWithNetworkCache = DYLD_MACOSX_VERSION_10_11,
     FirstWithExceptionsForDuplicateCompletionHandlerCalls = DYLD_MACOSX_VERSION_10_13,
index b2a9241..e1e93a6 100644 (file)
@@ -49,7 +49,6 @@ WebPreviewLoaderClient::WebPreviewLoaderClient(const String& fileName, const Str
     , m_uti { uti }
     , m_pageID { pageID }
 {
-    WebProcess::singleton().send(Messages::WebPageProxy::DidStartLoadForQuickLookDocumentInMainFrame(m_fileName, m_uti), m_pageID);
 }
 
 WebPreviewLoaderClient::~WebPreviewLoaderClient()
@@ -59,6 +58,9 @@ WebPreviewLoaderClient::~WebPreviewLoaderClient()
 
 void WebPreviewLoaderClient::didReceiveDataArray(CFArrayRef dataArray)
 {
+    if (m_data.isEmpty())
+        WebProcess::singleton().send(Messages::WebPageProxy::DidStartLoadForQuickLookDocumentInMainFrame(m_fileName, m_uti), m_pageID);
+
     CFArrayApplyFunction(dataArray, CFRangeMake(0, CFArrayGetCount(dataArray)), [](const void* value, void* context) {
         ASSERT(CFGetTypeID(value) == CFDataGetTypeID());
         static_cast<QuickLookDocumentData*>(context)->append((CFDataRef)value);
index 97ef32a..aa1c6f3 100644 (file)
@@ -1,3 +1,53 @@
+2019-03-31  Andy Estes  <aestes@apple.com>
+
+        [iOS] WebKit should consult the navigation response policy delegate before previewing a QuickLook document
+        https://bugs.webkit.org/show_bug.cgi?id=196433
+        <rdar://problem/49293305>
+
+        Reviewed by Tim Horton.
+
+        Enhanced API test coverage to include all navigation response policy decisions in both
+        linked-before and linked-on-or-after modes. Also added new expectations for all tests.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebCore/ios/PreviewConverter.cpp: Renamed from Tools/TestWebKitAPI/Tests/WebCore/ios/PreviewLoader.cpp.
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebKitCocoa/QuickLook.mm:
+        (readFile):
+        (-[QuickLookDelegate initWithExpectedFileURL:responsePolicy:]):
+        (-[QuickLookDelegate initWithExpectedFileURL:previewMIMEType:responsePolicy:]):
+        (-[QuickLookDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
+        (-[QuickLookDelegate _webView:didStartLoadForQuickLookDocumentInMainFrameWithFileName:uti:]):
+        (-[QuickLookDelegate _webView:didFinishLoadForQuickLookDocumentInMainFrame:]):
+        (-[QuickLookDelegate webView:didFailProvisionalNavigation:withError:]):
+        (-[QuickLookDelegate _webViewWebProcessDidCrash:]):
+        (-[QuickLookDelegate _downloadDidStart:]):
+        (-[QuickLookDelegate _download:didReceiveResponse:]):
+        (-[QuickLookDelegate _download:didReceiveData:]):
+        (-[QuickLookDelegate _download:decideDestinationWithSuggestedFilename:completionHandler:]):
+        (-[QuickLookDelegate _downloadDidFinish:]):
+        (-[QuickLookDelegate _download:didFailWithError:]):
+        (-[QuickLookDelegate _downloadDidCancel:]):
+        (-[QuickLookDelegate verifyDownload]):
+        (runTest):
+        (runTestDecideBeforeLoading):
+        (runTestDecideAfterLoading):
+        (TEST):
+        (-[QuickLookAsyncDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
+        (-[QuickLookPasswordDelegate _webViewDidRequestPasswordForQuickLookDocument:]):
+        (-[QuickLookFrameLoadDelegate webView:didFinishLoadForFrame:]):
+        (-[QuickLookNavigationDelegate _webView:didStartLoadForQuickLookDocumentInMainFrameWithFileName:uti:]): Deleted.
+        (-[QuickLookNavigationDelegate _webView:didFinishLoadForQuickLookDocumentInMainFrame:]): Deleted.
+        (-[QuickLookNavigationDelegate webView:didFinishNavigation:]): Deleted.
+        (-[QuickLookAsyncNavigationDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]): Deleted.
+        (-[QuickLookAsyncNavigationDelegate _webView:didStartLoadForQuickLookDocumentInMainFrameWithFileName:uti:]): Deleted.
+        (-[QuickLookAsyncNavigationDelegate _webView:didFinishLoadForQuickLookDocumentInMainFrame:]): Deleted.
+        (-[QuickLookAsyncNavigationDelegate webView:didFinishNavigation:]): Deleted.
+        (-[QuickLookDecidePolicyDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]): Deleted.
+        (-[QuickLookDecidePolicyDelegate webView:didFailProvisionalNavigation:withError:]): Deleted.
+        (-[QuickLookDecidePolicyDelegate _webViewWebProcessDidCrash:]): Deleted.
+        (-[QuickLookPasswordNavigationDelegate _webViewDidRequestPasswordForQuickLookDocument:]): Deleted.
+
 2019-03-30  Dominik Infuehr  <dinfuehr@igalia.com>
 
         [CMake] add testdfg as target with build-jsc
index 6a5255a..9d55759 100644 (file)
                A180C0FA1EE67DF000468F47 /* RunOpenPanel.mm in Sources */ = {isa = PBXBuildFile; fileRef = A180C0F91EE67DF000468F47 /* RunOpenPanel.mm */; };
                A1C4FB731BACD1CA003742D0 /* pages.pages in Copy Resources */ = {isa = PBXBuildFile; fileRef = A1C4FB721BACD1B7003742D0 /* pages.pages */; };
                A1DF74321C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A1DF74301C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm */; };
-               A1EC11881F42541200D0146E /* PreviewLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1EC11871F42541200D0146E /* PreviewLoader.cpp */; };
+               A1EC11881F42541200D0146E /* PreviewConverter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1EC11871F42541200D0146E /* PreviewConverter.cpp */; };
                A310827221F296FF00C28B97 /* FileSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A310827121F296EC00C28B97 /* FileSystem.cpp */; };
                A57A34F216AF6B2B00C2501F /* PageVisibilityStateWithWindowChanges.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = A57A34F116AF69E200C2501F /* PageVisibilityStateWithWindowChanges.html */; };
                A57D54F31F338C3600A97AA7 /* NeverDestroyed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A57D54F21F338C3600A97AA7 /* NeverDestroyed.cpp */; };
                A1C4FB6C1BACCE50003742D0 /* QuickLook.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QuickLook.mm; sourceTree = "<group>"; };
                A1C4FB721BACD1B7003742D0 /* pages.pages */ = {isa = PBXFileReference; lastKnownFileType = file; name = pages.pages; path = ios/pages.pages; sourceTree = SOURCE_ROOT; };
                A1DF74301C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AlwaysRevalidatedURLSchemes.mm; sourceTree = "<group>"; };
-               A1EC11871F42541200D0146E /* PreviewLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PreviewLoader.cpp; sourceTree = "<group>"; };
+               A1EC11871F42541200D0146E /* PreviewConverter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PreviewConverter.cpp; sourceTree = "<group>"; };
                A1FDFD2E19C288BB005148A4 /* WKImageCreateCGImageCrash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKImageCreateCGImageCrash.cpp; sourceTree = "<group>"; };
                A310827121F296EC00C28B97 /* FileSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileSystem.cpp; sourceTree = "<group>"; };
                A57A34EF16AF677200C2501F /* PageVisibilityStateWithWindowChanges.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PageVisibilityStateWithWindowChanges.mm; sourceTree = "<group>"; };
                A1EC11851F4253D900D0146E /* ios */ = {
                        isa = PBXGroup;
                        children = (
-                               A1EC11871F42541200D0146E /* PreviewLoader.cpp */,
+                               A1EC11871F42541200D0146E /* PreviewConverter.cpp */,
                        );
                        path = ios;
                        sourceTree = "<group>";
                                7C1AF7951E8DCBAB002645B9 /* PrepareForMoveToWindow.mm in Sources */,
                                7CCE7F0B1A411AE600447C4C /* PreventEmptyUserAgent.cpp in Sources */,
                                7CCE7F2C1A411B1000447C4C /* PreventImageLoadWithAutoResizing.mm in Sources */,
-                               A1EC11881F42541200D0146E /* PreviewLoader.cpp in Sources */,
+                               A1EC11881F42541200D0146E /* PreviewConverter.cpp in Sources */,
                                7CCE7F0C1A411AE600447C4C /* PrivateBrowsingPushStateNoHistoryCallback.cpp in Sources */,
                                4647B1261EBA3B850041D7EF /* ProcessDidTerminate.cpp in Sources */,
                                41882F0321010C0D002FF288 /* ProcessPreWarming.mm in Sources */,
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #if PLATFORM(IOS_FAMILY) && USE(QUICK_LOOK)
 
-#include <WebCore/PreviewLoader.h>
+#include <WebCore/PreviewConverter.h>
 #include <wtf/text/WTFString.h>
 
 using namespace WebCore;
 
 namespace TestWebKitAPI {
 
-TEST(QuickLook, ShouldCreateForMIMEType)
+TEST(QuickLook, SupportsMIMEType)
 {
     // FIXME: Expand this to cover all the MIME types we expect to support.
-    EXPECT_FALSE(PreviewLoader::shouldCreateForMIMEType(String()));
-    EXPECT_FALSE(PreviewLoader::shouldCreateForMIMEType(emptyString()));
-    EXPECT_TRUE(PreviewLoader::shouldCreateForMIMEType("application/vnd.ms-excel.sheet.macroEnabled.12"_s));
+    EXPECT_FALSE(PreviewConverter::supportsMIMEType(String()));
+    EXPECT_FALSE(PreviewConverter::supportsMIMEType(emptyString()));
+    EXPECT_FALSE(PreviewConverter::supportsMIMEType("text/html"_s));
+    EXPECT_FALSE(PreviewConverter::supportsMIMEType("text/plain"_s));
+    EXPECT_TRUE(PreviewConverter::supportsMIMEType("application/vnd.ms-excel.sheet.macroEnabled.12"_s));
 }
 
 } // namespace TestWebKitAPI
index 93d07fa..c477df3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #import "PlatformUtilities.h"
 #import "Test.h"
+#import <CoreServices/CoreServices.h>
 #import <WebCore/WebCoreThread.h>
 #import <WebKit/WKNavigationDelegatePrivate.h>
+#import <WebKit/WKProcessPoolPrivate.h>
+#import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/WebDataSourcePrivate.h>
 #import <WebKit/WebKit.h>
 #import <WebKit/WebPreferencesPrivate.h>
 #import <WebKit/WebUIKitSupport.h>
 #import <WebKit/WebViewPrivate.h>
+#import <WebKit/_WKDownload.h>
+#import <WebKit/_WKDownloadDelegate.h>
 #import <wtf/RetainPtr.h>
 
 using namespace TestWebKitAPI;
 
 static bool isDone;
-static bool didStartQuickLookLoad;
-static bool didFinishQuickLookLoad;
+static bool downloadIsDone;
 
-static const NSUInteger expectedFileSize = 274143;
-static NSString * const expectedFileName = @"pages.pages";
-static NSString * const expectedUTI = @"com.apple.iwork.pages.sffpages";
-static NSURLRequest * const pagesDocumentRequest = [[NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"pages" withExtension:@"pages" subdirectory:@"TestWebKitAPI.resources"]] retain];
+static NSString * const pagesDocumentPreviewMIMEType = @"application/pdf";
+static NSURL * const pagesDocumentURL = [[NSBundle.mainBundle URLForResource:@"pages" withExtension:@"pages" subdirectory:@"TestWebKitAPI.resources"] retain];
+
+@interface QuickLookDelegate : NSObject <WKNavigationDelegatePrivate, _WKDownloadDelegate>
+- (instancetype)init NS_UNAVAILABLE;
+- (instancetype)initWithExpectedFileURL:(NSURL *)fileURL responsePolicy:(WKNavigationResponsePolicy)responsePolicy;
+- (instancetype)initWithExpectedFileURL:(NSURL *)fileURL previewMIMEType:(NSString *)mimeType responsePolicy:(WKNavigationResponsePolicy)responsePolicy;
+- (void)verifyDownload;
+
+@property (nonatomic) BOOL didStartQuickLookLoad;
+@property (nonatomic) BOOL didFinishQuickLookLoad;
 
-@interface QuickLookNavigationDelegate : NSObject <WKNavigationDelegatePrivate>
 @end
 
-@implementation QuickLookNavigationDelegate
+@implementation QuickLookDelegate {
+@protected
+    NSUInteger _downloadFileSize;
+    NSUInteger _expectedFileSize;
+    RetainPtr<NSString> _expectedFileName;
+    RetainPtr<NSString> _expectedFileType;
+    RetainPtr<NSString> _expectedMIMEType;
+    RetainPtr<NSURL> _downloadDestinationURL;
+    WKNavigationResponsePolicy _responsePolicy;
+}
+
+static void readFile(NSURL *fileURL, NSUInteger& fileSize, RetainPtr<NSString>& fileName, RetainPtr<NSString>& fileType, RetainPtr<NSString>& mimeType)
+{
+    if (NSDictionary *attributes = [NSFileManager.defaultManager attributesOfItemAtPath:fileURL.path error:nil])
+        fileSize = [attributes[NSFileSize] unsignedIntegerValue];
+
+    fileName = fileURL.lastPathComponent;
+
+    NSString *typeIdentifier = nil;
+    if ([fileURL getResourceValue:&typeIdentifier forKey:NSURLTypeIdentifierKey error:nil])
+        fileType = typeIdentifier;
+
+    mimeType = adoptCF(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)typeIdentifier, kUTTagClassMIMEType));
+}
+
+- (instancetype)initWithExpectedFileURL:(NSURL *)fileURL responsePolicy:(WKNavigationResponsePolicy)responsePolicy
+{
+    if (!(self = [super init]))
+        return nil;
+
+    readFile(fileURL, _expectedFileSize, _expectedFileName, _expectedFileType, _expectedMIMEType);
+
+    _responsePolicy = responsePolicy;
+    return self;
+}
+
+- (instancetype)initWithExpectedFileURL:(NSURL *)fileURL previewMIMEType:(NSString *)mimeType responsePolicy:(WKNavigationResponsePolicy)responsePolicy
+{
+    if (!(self = [self initWithExpectedFileURL:fileURL responsePolicy:responsePolicy]))
+        return nil;
+    
+    _expectedMIMEType = mimeType;
+    return self;
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
+{
+    EXPECT_TRUE(navigationResponse.canShowMIMEType);
+    EXPECT_WK_STREQ(_expectedFileName.get(), navigationResponse.response.URL.lastPathComponent);
+    EXPECT_WK_STREQ(_expectedMIMEType.get(), navigationResponse.response.MIMEType);
+    decisionHandler(_responsePolicy);
+}
 
 - (void)_webView:(WKWebView *)webView didStartLoadForQuickLookDocumentInMainFrameWithFileName:(NSString *)fileName uti:(NSString *)uti
 {
-    EXPECT_WK_STREQ(expectedFileName, fileName);
-    EXPECT_WK_STREQ(expectedUTI, uti);
-    didStartQuickLookLoad = true;
+    EXPECT_FALSE(_didFinishQuickLookLoad);
+    EXPECT_FALSE(_didStartQuickLookLoad);
+    EXPECT_WK_STREQ(_expectedFileName.get(), fileName);
+    EXPECT_WK_STREQ(_expectedFileType.get(), uti);
+    _didStartQuickLookLoad = YES;
 }
 
 - (void)_webView:(WKWebView *)webView didFinishLoadForQuickLookDocumentInMainFrame:(NSData *)documentData
 {
-    EXPECT_EQ(expectedFileSize, documentData.length);
-    didFinishQuickLookLoad = true;
+    EXPECT_EQ(_expectedFileSize, documentData.length);
+    EXPECT_FALSE(_didFinishQuickLookLoad);
+    EXPECT_TRUE(_didStartQuickLookLoad);
+    _didFinishQuickLookLoad = YES;
 }
 
 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
@@ -72,128 +137,227 @@ static NSURLRequest * const pagesDocumentRequest = [[NSURLRequest requestWithURL
     isDone = true;
 }
 
-@end
+- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
+{
+    isDone = true;
+}
 
-@interface QuickLookAsyncNavigationDelegate : NSObject <WKNavigationDelegatePrivate>
-@end
+- (void)_webViewWebProcessDidCrash:(WKWebView *)webView
+{
+    RELEASE_ASSERT_NOT_REACHED();
+}
 
-@implementation QuickLookAsyncNavigationDelegate
+- (void)_downloadDidStart:(_WKDownload *)download
+{
+    EXPECT_WK_STREQ(_expectedFileName.get(), download.request.URL.lastPathComponent);
+}
 
-- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
+- (void)_download:(_WKDownload *)download didReceiveResponse:(NSURLResponse *)response
 {
-    int64_t deferredWaitTime = 100 * NSEC_PER_MSEC;
-    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, deferredWaitTime);
+    EXPECT_WK_STREQ(_expectedFileName.get(), response.URL.lastPathComponent);
+    EXPECT_WK_STREQ(_expectedMIMEType.get(), response.MIMEType);
+}
 
-    dispatch_after(when, dispatch_get_main_queue(), ^{
-        decisionHandler(WKNavigationResponsePolicyAllow);
-    });
+- (void)_download:(_WKDownload *)download didReceiveData:(uint64_t)length
+{
+    _downloadFileSize += length;
 }
 
-- (void)_webView:(WKWebView *)webView didStartLoadForQuickLookDocumentInMainFrameWithFileName:(NSString *)fileName uti:(NSString *)uti
+- (void)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename completionHandler:(void (^)(BOOL, NSString *))completionHandler
 {
-    EXPECT_WK_STREQ(expectedFileName, fileName);
-    EXPECT_WK_STREQ(expectedUTI, uti);
-    didStartQuickLookLoad = true;
+    EXPECT_WK_STREQ(_expectedFileName.get(), filename);
+    
+    NSURL *tempDirectoryURL = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
+    _downloadDestinationURL = [NSURL fileURLWithPath:filename relativeToURL:tempDirectoryURL];
+    completionHandler(YES, [_downloadDestinationURL path]);
 }
 
-- (void)_webView:(WKWebView *)webView didFinishLoadForQuickLookDocumentInMainFrame:(NSData *)documentData
+- (void)_downloadDidFinish:(_WKDownload *)download
 {
-    EXPECT_EQ(expectedFileSize, documentData.length);
-    didFinishQuickLookLoad = true;
+    EXPECT_EQ(_expectedFileSize, _downloadFileSize);
+    downloadIsDone = true;
 }
 
-- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
+- (void)_download:(_WKDownload *)download didFailWithError:(NSError *)error
 {
-    isDone = true;
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+- (void)_downloadDidCancel:(_WKDownload *)download
+{
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+- (void)verifyDownload
+{
+    EXPECT_TRUE([NSFileManager.defaultManager fileExistsAtPath:[_downloadDestinationURL path]]);
+
+    NSUInteger downloadFileSize;
+    RetainPtr<NSString> downloadFileName;
+    RetainPtr<NSString> downloadFileType;
+    RetainPtr<NSString> downloadMIMEType;
+    readFile(_downloadDestinationURL.get(), downloadFileSize, downloadFileName, downloadFileType, downloadMIMEType);
+
+    EXPECT_EQ(_expectedFileSize, downloadFileSize);
+    EXPECT_WK_STREQ(_expectedFileName.get(), downloadFileName.get());
+    EXPECT_WK_STREQ(_expectedFileType.get(), downloadFileType.get());
+    EXPECT_WK_STREQ(_expectedMIMEType.get(), downloadMIMEType.get());
 }
 
 @end
 
-static void runTest(Class navigationDelegateClass, NSURLRequest *request)
+static void runTest(QuickLookDelegate *delegate, NSURLRequest *request, BOOL shouldDecidePolicyBeforeLoading)
 {
-    auto webView = adoptNS([[WKWebView alloc] init]);
-    auto navigationDelegate = adoptNS([[navigationDelegateClass alloc] init]);
-    [webView setNavigationDelegate:navigationDelegate.get()];
+    auto processPool = adoptNS([[WKProcessPool alloc] init]);
+    [processPool _setDownloadDelegate:delegate];
+
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [configuration _setShouldDecidePolicyBeforeLoadingQuickLookPreview:shouldDecidePolicyBeforeLoading];
+    [configuration setProcessPool:processPool.get()];
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
+    [webView setNavigationDelegate:delegate];
     [webView loadRequest:request];
 
     isDone = false;
     Util::run(&isDone);
 }
 
-TEST(QuickLook, NavigationDelegate)
+static void runTestDecideBeforeLoading(QuickLookDelegate *delegate, NSURLRequest *request)
 {
-    runTest([QuickLookNavigationDelegate class], pagesDocumentRequest);
-    EXPECT_TRUE(didStartQuickLookLoad);
-    EXPECT_TRUE(didFinishQuickLookLoad);
+    runTest(delegate, request, YES);
 }
 
-TEST(QuickLook, AsyncNavigationDelegate)
+static void runTestDecideAfterLoading(QuickLookDelegate *delegate, NSURLRequest *request)
 {
-    runTest([QuickLookAsyncNavigationDelegate class], pagesDocumentRequest);
-    EXPECT_TRUE(didStartQuickLookLoad);
-    EXPECT_TRUE(didFinishQuickLookLoad);
+    runTest(delegate, request, NO);
 }
 
-@interface QuickLookDecidePolicyDelegate : NSObject <WKNavigationDelegate>
+TEST(QuickLook, AllowResponseBeforeLoadingPreview)
+{
+    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL responsePolicy:WKNavigationResponsePolicyAllow]);
+    runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
+    EXPECT_TRUE([delegate didStartQuickLookLoad]);
+    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
+}
+
+TEST(QuickLook, AllowResponseAfterLoadingPreview)
+{
+    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL previewMIMEType:pagesDocumentPreviewMIMEType responsePolicy:WKNavigationResponsePolicyAllow]);
+    runTestDecideAfterLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
+    EXPECT_TRUE([delegate didStartQuickLookLoad]);
+    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
+}
+
+@interface QuickLookAsyncDelegate : QuickLookDelegate
 @end
 
-@implementation QuickLookDecidePolicyDelegate
+@implementation QuickLookAsyncDelegate
 
 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
 {
-    decisionHandler(WKNavigationResponsePolicyCancel);
+    int64_t deferredWaitTime = 100 * NSEC_PER_MSEC;
+    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, deferredWaitTime);
+
+    dispatch_after(when, dispatch_get_main_queue(), ^{
+        decisionHandler(_responsePolicy);
+    });
 }
 
-- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
+@end
+
+TEST(QuickLook, AsyncAllowResponseBeforeLoadingPreview)
 {
-    isDone = true;
+    auto delegate = adoptNS([[QuickLookAsyncDelegate alloc] initWithExpectedFileURL:pagesDocumentURL responsePolicy:WKNavigationResponsePolicyAllow]);
+    runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
+    EXPECT_TRUE([delegate didStartQuickLookLoad]);
+    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
 }
 
-- (void)_webViewWebProcessDidCrash:(WKWebView *)webView
+TEST(QuickLook, AsyncAllowResponseAfterLoadingPreview)
 {
-    RELEASE_ASSERT_NOT_REACHED();
+    auto delegate = adoptNS([[QuickLookAsyncDelegate alloc] initWithExpectedFileURL:pagesDocumentURL previewMIMEType:pagesDocumentPreviewMIMEType responsePolicy:WKNavigationResponsePolicyAllow]);
+    runTestDecideAfterLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
+    EXPECT_TRUE([delegate didStartQuickLookLoad]);
+    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
 }
 
-@end
+TEST(QuickLook, CancelResponseBeforeLoadingPreview)
+{
+    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL responsePolicy:WKNavigationResponsePolicyCancel]);
+    runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
+    EXPECT_FALSE([delegate didStartQuickLookLoad]);
+    EXPECT_FALSE([delegate didFinishQuickLookLoad]);
+}
 
-@interface QuickLookFrameLoadDelegate : NSObject <WebFrameLoadDelegate>
-@end
+TEST(QuickLook, CancelResponseAfterLoadingPreview)
+{
+    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL previewMIMEType:pagesDocumentPreviewMIMEType responsePolicy:WKNavigationResponsePolicyCancel]);
+    runTestDecideAfterLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
+    EXPECT_TRUE([delegate didStartQuickLookLoad]);
+    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
+}
 
-@implementation QuickLookFrameLoadDelegate
+TEST(QuickLook, DownloadResponseBeforeLoadingPreview)
+{
+    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL responsePolicy:_WKNavigationResponsePolicyBecomeDownload]);
+    runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
+    EXPECT_FALSE([delegate didStartQuickLookLoad]);
+    EXPECT_FALSE([delegate didFinishQuickLookLoad]);
 
-- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+    Util::run(&downloadIsDone);
+    [delegate verifyDownload];
+}
+
+TEST(QuickLook, DownloadResponseAfterLoadingPreview)
 {
-    isDone = true;
+    auto delegate = adoptNS([[QuickLookDelegate alloc] initWithExpectedFileURL:pagesDocumentURL previewMIMEType:pagesDocumentPreviewMIMEType responsePolicy:_WKNavigationResponsePolicyBecomeDownload]);
+    runTestDecideAfterLoading(delegate.get(), [NSURLRequest requestWithURL:pagesDocumentURL]);
+    EXPECT_TRUE([delegate didStartQuickLookLoad]);
+    EXPECT_TRUE([delegate didFinishQuickLookLoad]);
 }
 
+@interface QuickLookPasswordDelegate : QuickLookDelegate
+@property (nonatomic) BOOL didRequestPassword;
 @end
 
-TEST(QuickLook, CancelNavigationAfterResponse)
+@implementation QuickLookPasswordDelegate
+
+- (void)_webViewDidRequestPasswordForQuickLookDocument:(WKWebView *)webView
 {
-    runTest([QuickLookDecidePolicyDelegate class], pagesDocumentRequest);
+    _didRequestPassword = YES;
+    isDone = true;
 }
 
-@interface QuickLookPasswordNavigationDelegate : NSObject <WKNavigationDelegatePrivate>
 @end
 
-@implementation QuickLookPasswordNavigationDelegate
+TEST(QuickLook, RequestPasswordBeforeLoadingPreview)
+{
+    NSURL *passwordProtectedDocumentURL = [NSBundle.mainBundle URLForResource:@"password-protected" withExtension:@"pages" subdirectory:@"TestWebKitAPI.resources"];
+    auto delegate = adoptNS([[QuickLookPasswordDelegate alloc] initWithExpectedFileURL:passwordProtectedDocumentURL responsePolicy:WKNavigationResponsePolicyAllow]);
+    runTestDecideBeforeLoading(delegate.get(), [NSURLRequest requestWithURL:passwordProtectedDocumentURL]);
+    EXPECT_TRUE([delegate didRequestPassword]);
+}
 
-- (void)_webViewDidRequestPasswordForQuickLookDocument:(WKWebView *)webView
+TEST(QuickLook, RequestPasswordAfterLoadingPreview)
 {
-    isDone = true;
+    NSURL *passwordProtectedDocumentURL = [NSBundle.mainBundle URLForResource:@"password-protected" withExtension:@"pages" subdirectory:@"TestWebKitAPI.resources"];
+    auto delegate = adoptNS([[QuickLookPasswordDelegate alloc] initWithExpectedFileURL:passwordProtectedDocumentURL previewMIMEType:pagesDocumentPreviewMIMEType responsePolicy:WKNavigationResponsePolicyAllow]);
+    runTestDecideAfterLoading(delegate.get(), [NSURLRequest requestWithURL:passwordProtectedDocumentURL]);
+    EXPECT_TRUE([delegate didRequestPassword]);
 }
 
+@interface QuickLookFrameLoadDelegate : NSObject <WebFrameLoadDelegate>
 @end
 
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
+@implementation QuickLookFrameLoadDelegate
 
-TEST(QuickLook, DidRequestPasswordNavigationDelegate)
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
 {
-    NSURLRequest *passwordProtectedDocumentRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"password-protected" withExtension:@"pages" subdirectory:@"TestWebKitAPI.resources"]];
-    runTest([QuickLookPasswordNavigationDelegate class], passwordProtectedDocumentRequest);
+    isDone = true;
 }
 
-#endif
+@end
 
 TEST(QuickLook, LegacyQuickLookContent)
 {
@@ -211,18 +375,23 @@ TEST(QuickLook, LegacyQuickLookContent)
 
     WebFrame *mainFrame = [webView mainFrame];
 
-    isDone = false;
-    [mainFrame loadRequest:pagesDocumentRequest];
+    [mainFrame loadRequest:[NSURLRequest requestWithURL:pagesDocumentURL]];
     Util::run(&isDone);
     WebThreadLock();
 
+    NSUInteger expectedFileSize;
+    RetainPtr<NSString> expectedFileName;
+    RetainPtr<NSString> expectedFileType;
+    RetainPtr<NSString> expectedMIMEType;
+    readFile(pagesDocumentURL, expectedFileSize, expectedFileName, expectedFileType, expectedMIMEType);
+
     NSDictionary *quickLookContent = mainFrame.dataSource._quickLookContent;
     NSString *filePath = quickLookContent[WebQuickLookFileNameKey];
-    EXPECT_TRUE([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
-    EXPECT_WK_STREQ(expectedFileName, filePath.lastPathComponent);
-    EXPECT_WK_STREQ(expectedUTI, quickLookContent[WebQuickLookUTIKey]);
+    EXPECT_TRUE([NSFileManager.defaultManager fileExistsAtPath:filePath]);
+    EXPECT_WK_STREQ(expectedFileName.get(), filePath.lastPathComponent);
+    EXPECT_WK_STREQ(expectedFileType.get(), quickLookContent[WebQuickLookUTIKey]);
 
-    NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
+    NSDictionary *fileAttributes = [NSFileManager.defaultManager attributesOfItemAtPath:filePath error:nil];
     EXPECT_EQ(expectedFileSize, [fileAttributes[NSFileSize] unsignedIntegerValue]);
 
     isDone = false;