CVE-2024-40857
Overview
Background
- Web Archive
- a single-file snapshot format (
application/x-webarchive,multipart/related, etc.) that bundles a page and its subresources, each of which declares its own origin. - `WebsiteDataStore`
- the object holding a browsing context’s persistent storage (cookies,
localStorage, IndexedDB, caches) for real web origins. - UXSS
- universal cross-site scripting, where attacker script executes in the security context of arbitrary origins rather than only the attacker’s own.
- `disallowWebArchive`
- the
DocumentLoadergate that decides whether a response with a web-archive MIME type is permitted to load into a frame.
Root Cause Analysis
A web archive can label its embedded resources with any origin it likes, so a document reconstructed from one runs with origins it never legitimately owned; the invariant that a document may only touch the storage of its true origin is therefore violated the moment the archive is loaded into the page’s normal, persistent WebsiteDataStore.
Before the fix, WebPageProxy::receivedNavigationActionPolicyDecision committed web-archive navigations directly into m_websiteDataStore, letting the spoofed origins read and write the persistent cookies and storage of real sites — a UXSS primitive.
The fix detects a web-archive load (by MIMETypeRegistry::isWebArchiveMIMEType on the substitute data, or a file: URL ending in .webarchive) and swaps in a freshly created non-persistent data store via WebsiteDataStore::createNonPersistent, forcing a process swap and remembering the replaced store on the back/forward item and provisional page so the isolation survives navigation. Because the archive now executes against ephemeral storage that shares nothing with the persistent origins, the spoofed content can no longer exfiltrate or poison real-origin state. In parallel, disallowWebArchive is hardened so the “always allow local web archive” bypass is a settings preference (settings().alwaysAllowLocalWebarchive(), defaulting false) rather than the loose per-FrameLoader test flag, and MIMETypeRegistry::isWebArchiveMIMEType guards its HashSet lookup with isValidValue.
WebsiteDataStore used by genuine web origins, so archive script inherited access to their real storage; the fix isolates every web-archive load in an ephemeral, non-persistent data store, severing that shared-storage bridge.Attack Path
- Craft a malicious archive
The attacker builds a
.webarchive(ormultipart/related) file whose embedded resources claim the origins of high-value target sites. - Deliver and open The victim is induced to open the local web archive, which WebKit treats as a local, same-origin-privileged document.
- Spoof target origins The reconstructed document executes script under the attacker-declared origins rather than the attacker’s own.
- Reach persistent storage
Loaded into the page’s persistent
WebsiteDataStore, that script reads and writes the cookies and site storage of the impersonated origins, achieving UXSS.
Impact Assessment
disallowWebArchive bypass remove the shared persistent storage that made the impersonation exploitable.Changed Functions
| Function | Change | Notes |
|---|---|---|
ProvisionalPageProxySource/WebKit/UIProcess/ProvisionalPageProxy.h |
modified |
Files Changed
Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yamlSource/WebCore/loader/DocumentLoader.cppSource/WebCore/loader/FrameLoader.cppSource/WebCore/loader/FrameLoader.hSource/WebCore/platform/MIMETypeRegistry.cppSource/WebCore/platform/MIMETypeRegistry.hSource/WebKit/Shared/LoadParameters.hSource/WebKit/Shared/LoadParameters.serialization.inSource/WebKit/Shared/WebBackForwardListItem.hSource/WebKit/UIProcess/ProvisionalPageProxy.cppSource/WebKit/UIProcess/ProvisionalPageProxy.hSource/WebKit/UIProcess/WebPageProxy.cpp
Audit Directions
- Origin-spoofing container formatsAudit every code path that reconstructs documents from bundled formats (web archives,
multipart/related, MHTML) to confirm they load into isolated, non-persistent storage and never inherit a persistentWebsiteDataStore. - MIME classification consistencyVerify all web-archive gates funnel through the single
MIMETypeRegistry::isWebArchiveMIMETypepredicate (with itsisValidValueguard) so no loader path re-implements a divergent or bypassable MIME check. - Data-store continuity across navigationCheck that swapped ephemeral stores survive process swaps, provisional-page commits, and back/forward navigation, since any path that reverts to the persistent store re-opens the storage-access bridge.
Patch
diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml
index 733d7c55c2c8..24d157779ff7 100644
--- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml
+++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml
@@ -453,6 +453,21 @@ AlternateWebMPlayerEnabled:
WebCore:
default: true
+AlwaysAllowLocalWebarchive:
+ type: bool
+ status: internal
+ category: dom
+ humanReadableName: "Always allow loading local Web Archive"
+ humanReadableDescription: "Enable always allowing loading local Web Archive"
+ condition: ENABLE(WEB_ARCHIVE)
+ defaultValue:
+ WebKitLegacy:
+ default: false
+ WebKit:
+ default: false
+ WebCore:
+ default: false
+
AlwaysZoomOnDoubleTap:
type: bool
status: internal
@@ -4098,6 +4113,21 @@ LoadDeferringEnabled:
WebCore:
default: true
+LoadWebArchiveWithEphemeralStorageEnabled:
+ type: bool
+ status: stable
+ category: dom
+ humanReadableName: "Load Web Archive with ephemeral storage"
+ humanReadableDescription: "Enable loading web archive with ephemeral storage"
+ condition: ENABLE(WEB_ARCHIVE)
+ defaultValue:
+ WebKitLegacy:
+ default: true
+ WebKit:
+ default: true
+ WebCore:
+ default: true
+
# This only suppresses the network load of the image URL. A cached image will still be rendered if requested.
LoadsImagesAutomatically:
type: bool
diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp
index 37b1847ad97c..6bb107154411 100644
--- a/Source/WebCore/loader/DocumentLoader.cpp
+++ b/Source/WebCore/loader/DocumentLoader.cpp
@@ -68,6 +68,7 @@
#include "LocalFrame.h"
#include "LocalFrameLoaderClient.h"
#include "Logging.h"
+#include "MIMETypeRegistry.h"
#include "MemoryCache.h"
#include "MixedContentChecker.h"
#include "NavigationRequester.h"
@@ -1053,20 +1054,8 @@ void DocumentLoader::responseReceived(const ResourceResponse& response, Completi
// because they can claim to be from any domain and thus avoid cross-domain security checks (4120255, 45524528, 47610130).
bool DocumentLoader::disallowWebArchive() const
{
- using MIMETypeHashSet = HashSet<String, ASCIICaseInsensitiveHash>;
- static NeverDestroyed<MIMETypeHashSet> webArchiveMIMETypes {
- MIMETypeHashSet {
- "application/x-webarchive"_s,
- "application/x-mimearchive"_s,
- "multipart/related"_s,
-#if PLATFORM(GTK)
- "message/rfc822"_s,
-#endif
- }
- };
-
String mimeType = m_response.mimeType();
- if (mimeType.isNull() || !webArchiveMIMETypes.get().contains(mimeType))
+ if (mimeType.isNull() || !MIMETypeRegistry::isWebArchiveMIMEType(mimeType))
return false;
#if USE(QUICK_LOOK)
@@ -1080,16 +1069,16 @@ bool DocumentLoader::disallowWebArchive() const
if (!LegacySchemeRegistry::shouldTreatURLSchemeAsLocal(m_request.url().protocol()))
return true;
- if (!frame() || (frame()->isMainFrame() && allowsWebArchiveForMainFrame()))
- return false;
-
+#if ENABLE(WEB_ARCHIVE)
// On purpose of maintaining existing tests.
auto* localFrame = dynamicDowncast<LocalFrame>(frame()->mainFrame());
- if (!localFrame)
+ bool alwaysAllowLocalWebArchive = localFrame && localFrame->settings().alwaysAllowLocalWebarchive();
+#else
+ bool alwaysAllowLocalWebArchive { false };
+#endif
+ if (!frame() || (frame()->isMainFrame() && allowsWebArchiveForMainFrame()) || alwaysAllowLocalWebArchive)
return false;
- if (localFrame->loader().alwaysAllowLocalWebarchive())
- return false;
return true;
}
diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp
index f6b1de47db25..d6e322fc3556 100644
--- a/Source/WebCore/loader/FrameLoader.cpp
+++ b/Source/WebCore/loader/FrameLoader.cpp
@@ -1634,6 +1634,7 @@ void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, Navig
Ref loader = m_client->createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
applyShouldOpenExternalURLsPolicyToNewDocumentLoader(m_frame, loader, action.initiatedByMainFrame(), action.shouldOpenExternalURLsPolicy());
loader->setIsContinuingLoadAfterProvisionalLoadStarted(shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::YesAfterProvisionalLoadStarted);
+ loader->setIsRequestFromClientOrUserInput(action.isRequestFromClientOrUserInput());
if (action.lockHistory() == LockHistory::Yes && m_documentLoader)
loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
@@ -4220,7 +4221,7 @@ void FrameLoader::loadDifferentDocumentItem(HistoryItem& item, HistoryItem* from
ResourceRequest requestForOriginalURL(request);
requestForOriginalURL.setURL(itemOriginalURL);
- action = { frame->protectedDocument().releaseNonNull(), requestForOriginalURL, initiatedByMainFrame, false, loadType, isFormSubmission, nullptr, shouldOpenExternalURLsPolicy };
+ action = { frame->protectedDocument().releaseNonNull(), requestForOriginalURL, initiatedByMainFrame, request.isAppInitiated(), loadType, isFormSubmission, nullptr, shouldOpenExternalURLsPolicy };
}
action.setTargetBackForwardItem(item);
diff --git a/Source/WebCore/loader/FrameLoader.h b/Source/WebCore/loader/FrameLoader.h
index 6f95aa23e0c0..cff0ad5b0430 100644
--- a/Source/WebCore/loader/FrameLoader.h
+++ b/Source/WebCore/loader/FrameLoader.h
@@ -336,6 +336,7 @@ public:
bool isReloadingFromOrigin() const { return m_loadType == FrameLoadType::ReloadFromOrigin; }
// Used in webarchive loading tests.
+ // FIXME: Clean up uses of setAlwaysAllowLocalWebarchive. The AlwaysAllowLocalWebarchive preference replaces it.
void setAlwaysAllowLocalWebarchive(bool alwaysAllowLocalWebarchive) { m_alwaysAllowLocalWebarchive = alwaysAllowLocalWebarchive; }
bool alwaysAllowLocalWebarchive() const { return m_alwaysAllowLocalWebarchive; }
diff --git a/Source/WebCore/platform/MIMETypeRegistry.cpp b/Source/WebCore/platform/MIMETypeRegistry.cpp
index 9dda8a21f402..d81810e950bb 100644
--- a/Source/WebCore/platform/MIMETypeRegistry.cpp
+++ b/Source/WebCore/platform/MIMETypeRegistry.cpp
@@ -841,4 +841,20 @@ bool MIMETypeRegistry::isJPEGMIMEType(const String& mimeType)
#endif
}
+bool MIMETypeRegistry::isWebArchiveMIMEType(const String& mimeType)
+{
+ using MIMETypeHashSet = HashSet<String, ASCIICaseInsensitiveHash>;
+ static NeverDestroyed<MIMETypeHashSet> webArchiveMIMETypes {
+ MIMETypeHashSet {
+ "application/x-webarchive"_s,
+ "application/x-mimearchive"_s,
+ "multipart/related"_s,
+#if PLATFORM(GTK)
+ "message/rfc822"_s,
+#endif
+ }
+ };
+
+ return webArchiveMIMETypes.get().isValidValue(mimeType) ? webArchiveMIMETypes.get().contains(mimeType) : false;
+}
} // namespace WebCore
diff --git a/Source/WebCore/platform/MIMETypeRegistry.h b/Source/WebCore/platform/MIMETypeRegistry.h
index b6e94c4ce0a4..4dac91f0428e 100644
--- a/Source/WebCore/platform/MIMETypeRegistry.h
+++ b/Source/WebCore/platform/MIMETypeRegistry.h
@@ -144,6 +144,7 @@ public:
WEBCORE_EXPORT static Vector<String> allowedMIMETypes(const Vector<String>& mimeTypes, const Vector<String>& extensions);
WEBCORE_EXPORT static Vector<String> allowedFileExtensions(const Vector<String>& mimeTypes, const Vector<String>& extensions);
WEBCORE_EXPORT static bool isJPEGMIMEType(const String& mimeType);
+ WEBCORE_EXPORT static bool isWebArchiveMIMEType(const String& mimeType);
private:
// Check to see if the MIME type is not suitable for being loaded as a text
// document in a frame. Only valid for MIME types begining with "text/".
diff --git a/Source/WebKit/Shared/LoadParameters.h b/Source/WebKit/Shared/LoadParameters.h
index f4a285c6317d..206d26984518 100644
--- a/Source/WebKit/Shared/LoadParameters.h
+++ b/Source/WebKit/Shared/LoadParameters.h
@@ -87,6 +87,7 @@ struct LoadParameters {
#if PLATFORM(COCOA)
std::optional<double> dataDetectionReferenceDate;
#endif
+ bool isRequestFromClientOrUserInput { false };
OptionSet<WebCore::AdvancedPrivacyProtections> advancedPrivacyProtections;
};
diff --git a/Source/WebKit/Shared/LoadParameters.serialization.in b/Source/WebKit/Shared/LoadParameters.serialization.in
index ef519c0c4176..7347f4dc8c3b 100644
--- a/Source/WebKit/Shared/LoadParameters.serialization.in
+++ b/Source/WebKit/Shared/LoadParameters.serialization.in
@@ -52,6 +52,7 @@
#if PLATFORM(COCOA)
std::optional<double> dataDetectionReferenceDate;
#endif
+ bool isRequestFromClientOrUserInput;
OptionSet<WebCore::AdvancedPrivacyProtections> advancedPrivacyProtections;
};
diff --git a/Source/WebKit/Shared/WebBackForwardListItem.h b/Source/WebKit/Shared/WebBackForwardListItem.h
index c6a74a3d6fda..ffefca1ee54a 100644
--- a/Source/WebKit/Shared/WebBackForwardListItem.h
+++ b/Source/WebKit/Shared/WebBackForwardListItem.h
@@ -28,6 +28,7 @@
#include "APIObject.h"
#include "SessionState.h"
#include "WebPageProxyIdentifier.h"
+#include "WebsiteDataStore.h"
#include <wtf/CheckedPtr.h>
#include <wtf/Ref.h>
#include <wtf/WeakPtr.h>
@@ -72,6 +73,8 @@ public:
const URL& resourceDirectoryURL() const { return m_resourceDirectoryURL; }
void setResourceDirectoryURL(URL&& url) { m_resourceDirectoryURL = WTFMove(url); }
+ RefPtr<WebsiteDataStore> dataStoreForWebArchive() const { return m_dataStoreForWebArchive; }
+ void setDataStoreForWebArchive(WebsiteDataStore* dataStore) { m_dataStoreForWebArchive = dataStore; }
bool itemIsInSameDocument(const WebBackForwardListItem&) const;
bool itemIsClone(const WebBackForwardListItem&);
@@ -99,6 +102,8 @@ private:
friend class WebBackForwardCache;
void setBackForwardCacheEntry(std::unique_ptr<WebBackForwardCacheEntry>&&);
+ RefPtr<WebsiteDataStore> m_dataStoreForWebArchive;
+
BackForwardListItemState m_itemState;
URL m_resourceDirectoryURL;
WebPageProxyIdentifier m_pageID;
diff --git a/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp b/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp
index b399af0b484f..0503086391fb 100644
--- a/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp
+++ b/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp
@@ -33,6 +33,7 @@
#include "FormDataReference.h"
#include "GoToBackForwardItemParameters.h"
#include "HandleMessage.h"
+#include "LoadedWebArchive.h"
#include "LocalFrameCreationParameters.h"
#include "Logging.h"
#include "MessageSenderInlines.h"
@@ -67,10 +68,11 @@ using namespace WebCore;
#define PROVISIONALPAGEPROXY_RELEASE_LOG(channel, fmt, ...) RELEASE_LOG(channel, "%p - [pageProxyID=%" PRIu64 ", webPageID=%" PRIu64 ", PID=%i, navigationID=%" PRIu64 "] ProvisionalPageProxy::" fmt, this, m_page->identifier().toUInt64(), m_webPageID.toUInt64(), m_process->processID(), m_navigationID, ##__VA_ARGS__)
#define PROVISIONALPAGEPROXY_RELEASE_LOG_ERROR(channel, fmt, ...) RELEASE_LOG_ERROR(channel, "%p - [pageProxyID=%" PRIu64 ", webPageID=%" PRIu64 ", PID=%i, navigationID=%" PRIu64 "] ProvisionalPageProxy::" fmt, this, m_page->identifier().toUInt64(), m_webPageID.toUInt64(), m_process->processID(), m_navigationID, ##__VA_ARGS__)
-ProvisionalPageProxy::ProvisionalPageProxy(WebPageProxy& page, Ref<WebProcessProxy>&& process, std::unique_ptr<SuspendedPageProxy> suspendedPage, API::Navigation& navigation, bool isServerRedirect, const WebCore::ResourceRequest& request, ProcessSwapRequestedByClient processSwapRequestedByClient, bool isProcessSwappingOnNavigationResponse, API::WebsitePolicies* websitePolicies)
+ProvisionalPageProxy::ProvisionalPageProxy(WebPageProxy& page, Ref<WebProcessProxy>&& process, std::unique_ptr<SuspendedPageProxy> suspendedPage, API::Navigation& navigation, bool isServerRedirect, const WebCore::ResourceRequest& request, ProcessSwapRequestedByClient processSwapRequestedByClient, bool isProcessSwappingOnNavigationResponse, API::WebsitePolicies* websitePolicies, WebsiteDataStore* replacedDataStoreForWebArchiveLoad)
: m_page(page)
, m_webPageID(suspendedPage ? suspendedPage->webPageID() : PageIdentifier::generate())
, m_process(WTFMove(process))
+ , m_replacedDataStoreForWebArchiveLoad(replacedDataStoreForWebArchiveLoad)
, m_navigationID(navigation.navigationID())
, m_isServerRedirect(isServerRedirect)
, m_request(request)
@@ -527,7 +529,7 @@ void ProvisionalPageProxy::logDiagnosticMessageWithValueDictionaryFromWebProcess
void ProvisionalPageProxy::backForwardAddItem(BackForwardListItemState&& itemState)
{
- m_page->backForwardAddItemShared(m_process.copyRef(), WTFMove(itemState));
+ m_page->backForwardAddItemShared(m_process.copyRef(), WTFMove(itemState), m_replacedDataStoreForWebArchiveLoad ? LoadedWebArchive::Yes : LoadedWebArchive::No);
}
void ProvisionalPageProxy::didDestroyNavigation(uint64_t navigationID)
diff --git a/Source/WebKit/UIProcess/ProvisionalPageProxy.h b/Source/WebKit/UIProcess/ProvisionalPageProxy.h
index 03f5c5a41322..deecd76a2024 100644
--- a/Source/WebKit/UIProcess/ProvisionalPageProxy.h
+++ b/Source/WebKit/UIProcess/ProvisionalPageProxy.h
@@ -83,7 +83,7 @@ using LayerHostingContextID = uint32_t;
class ProvisionalPageProxy : public IPC::MessageReceiver, public IPC::MessageSender {
WTF_MAKE_FAST_ALLOCATED;
public:
- ProvisionalPageProxy(WebPageProxy&, Ref<WebProcessProxy>&&, std::unique_ptr<SuspendedPageProxy>, API::Navigation&, bool isServerRedirect, const WebCore::ResourceRequest&, ProcessSwapRequestedByClient, bool isProcessSwappingOnNavigationResponse, API::WebsitePolicies*);
+ ProvisionalPageProxy(WebPageProxy&, Ref<WebProcessProxy>&&, std::unique_ptr<SuspendedPageProxy>, API::Navigation&, bool isServerRedirect, const WebCore::ResourceRequest&, ProcessSwapRequestedByClient, bool isProcessSwappingOnNavigationResponse, API::WebsitePolicies*, WebsiteDataStore* replacedDataStoreForWebArchiveLoad = nullptr);
~ProvisionalPageProxy();
WebPageProxy& page() { return m_page.get(); }
@@ -98,6 +98,7 @@ public:
ProcessSwapRequestedByClient processSwapRequestedByClient() const { return m_processSwapRequestedByClient; }
uint64_t navigationID() const { return m_navigationID; }
const URL& provisionalURL() const { return m_provisionalLoadURL; }
+ RefPtr<WebsiteDataStore> replacedDataStoreForWebArchiveLoad() const { return m_replacedDataStoreForWebArchiveLoad; }
bool isProcessSwappingOnNavigationResponse() const { return m_isProcessSwappingOnNavigationResponse; }
@@ -194,6 +195,7 @@ private:
std::unique_ptr<DrawingAreaProxy> m_drawingArea;
RefPtr<WebFrameProxy> m_mainFrame;
RefPtr<BrowsingContextGroup> m_browsingContextGroup;
+ RefPtr<WebsiteDataStore> m_replacedDataStoreForWebArchiveLoad;
RemotePageProxyState m_remotePageProxyState;
uint64_t m_navigationID;
bool m_isServerRedirect;
diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp
index 6ce5c9aaa948..ae4532b1d8da 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.cpp
+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp
@@ -1248,6 +1248,10 @@ void WebPageProxy::swapToProvisionalPage(std::unique_ptr<ProvisionalPageProxy> p
protectedPageClient()->didChangeWebPageID();
ASSERT(m_process->websiteDataStore());
m_websiteDataStore = *m_process->websiteDataStore();
+#if ENABLE(WEB_ARCHIVE)
+ if (provisionalPage->replacedDataStoreForWebArchiveLoad())
+ m_replacedDataStoreForWebArchiveLoad = provisionalPage->replacedDataStoreForWebArchiveLoad();
+#endif
#if HAVE(VISIBILITY_PROPAGATION_VIEW)
m_contextIDForVisibilityPropagationInWebProcess = provisionalPage->contextIDForVisibilityPropagationInWebProcess();
@@ -1791,6 +1795,7 @@ void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& proces
loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
loadParameters.existingNetworkResourceLoadIdentifierToResume = existingNetworkResourceLoadIdentifierToResume;
loadParameters.advancedPrivacyProtections = navigation.originatorAdvancedPrivacyProtections();
+ loadParameters.isRequestFromClientOrUserInput = navigation.isRequestFromClientOrUserInput() || shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::No;
maybeInitializeSandboxExtensionHandle(process, url, internals().pageLoadState.resourceDirectoryURL(), loadParameters.sandboxExtensionHandle);
prepareToLoadWebPage(process, loadParameters);
@@ -1866,6 +1871,7 @@ RefPtr<API::Navigation> WebPageProxy::loadFile(const String& fileURLString, cons
#if ENABLE(PUBLIC_SUFFIX_LIST)
loadParameters.topPrivatelyControlledDomain = WebCore::topPrivatelyControlledDomain(loadParameters.request.url().host().toString());
#endif
+ loadParameters.isRequestFromClientOrUserInput = isAppInitiated;
const bool checkAssumedReadAccessToResourceURL = false;
Ref process = m_process;
maybeInitializeSandboxExtensionHandle(process, fileURL, resourceDirectoryURL, loadParameters.sandboxExtensionHandle, checkAssumedReadAccessToResourceURL);
@@ -4208,10 +4214,12 @@ void WebPageProxy::receivedNavigationActionPolicyDecision(WebProcessProxy& proce
WEBPAGEPROXY_RELEASE_LOG(Loading, "receivedNavigationActionPolicyDecision: frameID=%" PRIu64 ", isMainFrame=%d, navigationID=%" PRIu64 ", policyAction=%u", frame.frameID().object().toUInt64(), frame.isMainFrame(), navigation ? navigation->navigationID() : 0, (unsigned)policyAction);
Ref websiteDataStore = m_websiteDataStore;
+ bool isPolicyDataStore { false };
if (RefPtr policies = navigation->websitePolicies()) {
if (policies->websiteDataStore() && policies->websiteDataStore() != websiteDataStore.ptr()) {
websiteDataStore = *policies->websiteDataStore();
processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
+ isPolicyDataStore = true;
}
if (policies->userContentController() && policies->userContentController() != m_userContentController.ptr())
processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
@@ -4263,6 +4271,33 @@ void WebPageProxy::receivedNavigationActionPolicyDecision(WebProcessProxy& proce
return;
}
+ RefPtr<WebsiteDataStore> replacedDataStoreForWebArchiveLoad;
+ LoadedWebArchive loadedWebArchive { LoadedWebArchive::No };
+#if ENABLE(WEB_ARCHIVE)
+ if (preferences().loadWebArchiveWithEphemeralStorageEnabled() && navigation && policyAction == PolicyAction::Use && navigationAction->navigationType() != NavigationType::Reload && !isPolicyDataStore) {
+ bool isSubstituteWebArchive = navigation->substituteData() && MIMETypeRegistry::isWebArchiveMIMEType(navigation->substituteData()->MIMEType);
+ auto webarchiveURL = isSubstituteWebArchive ? URL { navigation->substituteData()->baseURL } : navigation->currentRequest().url();
+ if (isSubstituteWebArchive || (webarchiveURL.protocolIsFile() && webarchiveURL.string().endsWith(".webarchive"_s))) {
+ WEBPAGEPROXY_RELEASE_LOG(Loading, "receivedNavigationActionPolicyDecision: Swapping in non-persistent websiteDataStore for web archive.");
+ if (navigation->targetItem() && navigation->targetItem()->dataStoreForWebArchive())
+ websiteDataStore = *navigation->targetItem()->dataStoreForWebArchive();
+ else {
+ auto nonPersistentDataStore = WebsiteDataStore::createNonPersistent();
+ replacedDataStoreForWebArchiveLoad = websiteDataStore.ptr();
+ websiteDataStore = WTFMove(nonPersistentDataStore);
+ processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
+ }
+ loadedWebArchive = LoadedWebArchive::Yes;
+ } else if (didLoadWebArchive()) {
+ websiteDataStore = m_replacedDataStoreForWebArchiveLoad.releaseNonNull();
+ m_replacedDataStoreForWebArchiveLoad = nullptr;
+ processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
+ }
+ }
+#else
+ UNUSED_VARIABLE(isPolicyDataStore);
+#endif
+
URL sourceURL { pageLoadState().url() };
if (auto* provisionalPage = provisionalPageProxy()) {
if (provisionalPage->navigationID() == navigation->navigationID())
@@ -4283,7 +4318,9 @@ void WebPageProxy::receivedNavigationActionPolicyDecision(WebProcessProxy& proce
processSwapRequestedByClient,
frame = Ref { frame },
processInitiatingNavigation = Ref { processInitiatingNavigation },
- message = WTFMove(message)
+ message = WTFMove(message),
+ loadedWebArchive,
+ replacedDataStoreForWebArchiveLoad
] (Ref<WebProcessProxy>&& processNavigatingTo, SuspendedPageProxy* destinationSuspendedPage, ASCIILiteral reason) mutable {
// If the navigation has been destroyed, then no need to proceed.
if (isClosed() || !navigationState().hasNavigation(navigation->navigationID())) {
@@ -4319,7 +4356,7 @@ void WebPageProxy::receivedNavigationActionPolicyDecision(WebProcessProxy& proce
if (suspendedPage && suspendedPage->pageIsClosedOrClosing())
suspendedPage = nullptr;
- continueNavigationInNewProcess(navigation, frame.get(), WTFMove(suspendedPage), WTFMove(processNavigatingTo), processSwapRequestedByClient, ShouldTreatAsContinuingLoad::YesAfterNavigationPolicyDecision, std::nullopt);
+ continueNavigationInNewProcess(navigation, frame.get(), WTFMove(suspendedPage), WTFMove(processNavigatingTo), processSwapRequestedByClient, ShouldTreatAsContinuingLoad::YesAfterNavigationPolicyDecision, std::nullopt, loadedWebArchive, replacedDataStoreForWebArchiveLoad.get());
receivedPolicyDecision(policyAction, navigation.ptr(), nullptr, WTFMove(navigationAction), WillContinueLoadInNewProcess::Yes, std::nullopt, WTFMove(message), WTFMove(completionHandler));
return;
@@ -4331,6 +4368,7 @@ void WebPageProxy::receivedNavigationActionPolicyDecision(WebProcessProxy& proce
loadParameters.request = navigation->currentRequest();
loadParameters.shouldTreatAsContinuingLoad = WebCore::ShouldTreatAsContinuingLoad::YesAfterNavigationPolicyDecision;
loadParameters.frameIdentifier = frame->frameID();
+ loadParameters.isRequestFromClientOrUserInput = navigationAction->data().isRequestFromClientOrUserInput;
processNavigatingTo->send(Messages::WebPage::LoadRequest(WTFMove(loadParameters)), webPageID());
}
@@ -4472,7 +4510,7 @@ void WebPageProxy::destroyProvisionalPage()
m_provisionalPage = nullptr;
... (file diff truncated)
Regression Test / PoC
diff --git a/LayoutTests/platform/ios/TestExpectations b/LayoutTests/platform/ios/TestExpectations
index 1a01d0af7fad..a4f87d04ce7a 100644
--- a/LayoutTests/platform/ios/TestExpectations
+++ b/LayoutTests/platform/ios/TestExpectations
@@ -1548,9 +1548,6 @@ webarchive/test-css-url-resources-in-stylesheets.html [ Failure ]
webarchive/test-css-url-resources-inline-styles.html [ Failure ]
webarchive/test-link-rel-icon.html [ Failure ]
-# The following two tests are expected to fail until <rdar://problem/34063313> is available on test systems.
-webarchive/loading/cache-expired-subresource.html [ Failure ]
-
# Webarchive tests that fail due to <https://bugs.webkit.org/show_bug.cgi?id=82665>:
http/tests/webarchive/test-css-url-encoding-shift-jis.html
http/tests/webarchive/test-css-url-encoding-utf-8.html
diff --git a/LayoutTests/platform/ios/webarchive/loading/cache-expired-subresource-expected.txt b/LayoutTests/platform/ios/webarchive/loading/cache-expired-subresource-expected.txt
index 2bfa51ed620c..e91452ddb29c 100644
--- a/LayoutTests/platform/ios/webarchive/loading/cache-expired-subresource-expected.txt
+++ b/LayoutTests/platform/ios/webarchive/loading/cache-expired-subresource-expected.txt
@@ -1,15 +1,15 @@
main frame - didStartProvisionalLoadForFrame
main frame - didCommitLoadForFrame
-frame "<!--frame1-->" - didStartProvisionalLoadForFrame
-resources/cache-expired-subresource.webarchive - willSendRequest <NSURLRequest URL resources/cache-expired-subresource.webarchive, main document URL cache-expired-subresource.html, http method GET> redirectResponse (null)
main frame - didFinishDocumentLoadForFrame
cache-expired-subresource.html - didFinishLoading
+frame "<!--frame1-->" - didStartProvisionalLoadForFrame
+resources/cache-expired-subresource.webarchive - willSendRequest <NSURLRequest URL resources/cache-expired-subresource.webarchive, main document URL cache-expired-subresource.html, http method GET> redirectResponse (null)
resources/cache-expired-subresource.webarchive - didReceiveResponse <NSURLResponse resources/cache-expired-subresource.webarchive, http status code 0>
frame "<!--frame1-->" - didCommitLoadForFrame
http://localhost/pink-bullet.png - willSendRequest <NSURLRequest URL http://localhost/pink-bullet.png, main document URL cache-expired-subresource.html, http method GET> redirectResponse (null)
frame "<!--frame1-->" - didFinishDocumentLoadForFrame
resources/cache-expired-subresource.webarchive - didFinishLoading
-http://localhost/pink-bullet.png - didReceiveResponse <NSURLResponse http://localhost/pink-bullet.png, http status code 0>
+http://localhost/pink-bullet.png - didReceiveResponse <NSURLResponse http://localhost/pink-bullet.png, http status code 200>
http://localhost/pink-bullet.png - didFinishLoading
frame "<!--frame1-->" - didHandleOnloadEventsForFrame
main frame - didHandleOnloadEventsForFrame
@@ -28,14 +28,14 @@ layer at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 284x134
RenderText {#text} at (0,0) size 240x19
text run at (0,0) width 240: "This page has a small pink circle in it"
- RenderBR {BR} at (239,15) size 1x0
+ RenderBR {BR} at (239,0) size 1x19
RenderImage {IMG} at (0,20) size 11x9
- RenderBR {BR} at (11,29) size 0x0
+ RenderBR {BR} at (11,14) size 0x19
RenderText {#text} at (0,29) size 163x19
text run at (0,29) width 107: "See, right there! "
text run at (106,29) width 57: "A circle!"
- RenderBR {BR} at (162,44) size 1x0
- RenderBR {BR} at (304,154) size 0x0
+ RenderBR {BR} at (162,29) size 1x19
+ RenderBR {BR} at (304,139) size 0x19
RenderText {#text} at (0,154) size 736x39
text run at (0,154) width 736: "This tests that loading a webarchive with a subresource that has an expired cache header does not attempt to hit the"
text run at (0,174) width 364: "network for resource, and actually uses the archived data"
diff --git a/LayoutTests/platform/mac-wk1/TestExpectations b/LayoutTests/platform/mac-wk1/TestExpectations
index 0c0d3a7deaab..ad65b1db3d3e 100644
--- a/LayoutTests/platform/mac-wk1/TestExpectations
+++ b/LayoutTests/platform/mac-wk1/TestExpectations
@@ -1465,6 +1465,9 @@ imported/w3c/web-platform-tests/cookies/secure/set-from-ws.sub.html [ Failure ]
webkit.org/b/244308 imported/w3c/web-platform-tests/cookies/attributes/attributes-ctl.sub.html [ Pass Failure ]
+# Only flakey in WK1
+webarchive/loading/test-loading-archive-subresource-null-mimetype.html [ Failure Pass ]
+
# WebKit1 frames use native scrollbars causing these tests to fail.
# Lack of ways to control the cross-frame scroll chaining in WK1.
diff --git a/LayoutTests/platform/mac-wk1/webarchive/loading/test-loading-archive-subresource-expected.txt b/LayoutTests/platform/mac-wk1/webarchive/loading/test-loading-archive-subresource-expected.txt
index 311f51997006..f92ab41e5c82 100644
--- a/LayoutTests/platform/mac-wk1/webarchive/loading/test-loading-archive-subresource-expected.txt
+++ b/LayoutTests/platform/mac-wk1/webarchive/loading/test-loading-archive-subresource-expected.txt
@@ -2,7 +2,10 @@ main frame - didStartProvisionalLoadForFrame
main frame - didCommitLoadForFrame
frame "<!--frame1-->" - didStartProvisionalLoadForFrame
main frame - didFinishDocumentLoadForFrame
+frame "<!--frame1-->" - didCommitLoadForFrame
+frame "<!--frame1-->" - didFinishDocumentLoadForFrame
+frame "<!--frame1-->" - didHandleOnloadEventsForFrame
main frame - didHandleOnloadEventsForFrame
-frame "<!--frame1-->" - didFailProvisionalLoadWithError
+frame "<!--frame1-->" - didFinishLoadForFrame
main frame - didFinishLoadForFrame
This test assumes the webarchive is not loaded.
diff --git a/LayoutTests/platform/mac-wk2/webarchive/loading/cache-expired-subresource-expected.txt b/LayoutTests/platform/mac-wk2/webarchive/loading/cache-expired-subresource-expected.txt
new file mode 100644
index 000000000000..be965e1e74aa
--- /dev/null
+++ b/LayoutTests/platform/mac-wk2/webarchive/loading/cache-expired-subresource-expected.txt
@@ -0,0 +1,41 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didFinishDocumentLoadForFrame
+cache-expired-subresource.html - didFinishLoading
+frame "<!--frame1-->" - didStartProvisionalLoadForFrame
+resources/cache-expired-subresource.webarchive - willSendRequest <NSURLRequest URL resources/cache-expired-subresource.webarchive, main document URL cache-expired-subresource.html, http method GET> redirectResponse (null)
+resources/cache-expired-subresource.webarchive - didReceiveResponse <NSURLResponse resources/cache-expired-subresource.webarchive, http status code 0>
+frame "<!--frame1-->" - didCommitLoadForFrame
+http://localhost/pink-bullet.png - willSendRequest <NSURLRequest URL http://localhost/pink-bullet.png, main document URL cache-expired-subresource.html, http method GET> redirectResponse (null)
+frame "<!--frame1-->" - didFinishDocumentLoadForFrame
+resources/cache-expired-subresource.webarchive - didFinishLoading
+http://localhost/pink-bullet.png - didReceiveResponse <NSURLResponse http://localhost/pink-bullet.png, http status code 200>
+http://localhost/pink-bullet.png - didFinishLoading
+frame "<!--frame1-->" - didHandleOnloadEventsForFrame
+main frame - didHandleOnloadEventsForFrame
+frame "<!--frame1-->" - didFinishLoadForFrame
+main frame - didFinishLoadForFrame
+layer at (0,0) size 800x600
+ RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+ RenderBlock {HTML} at (0,0) size 800x600
+ RenderBody {BODY} at (8,8) size 784x584
+ RenderIFrame {IFRAME} at (0,0) size 304x154 [border: (2px inset #000000)]
+ layer at (0,0) size 300x150
+ RenderView at (0,0) size 300x150
+ layer at (0,0) size 300x150
+ RenderBlock {HTML} at (0,0) size 300x150
+ RenderBody {BODY} at (8,8) size 284x134
+ RenderText {#text} at (0,0) size 240x18
+ text run at (0,0) width 240: "This page has a small pink circle in it"
+ RenderBR {BR} at (239,0) size 1x18
+ RenderImage {IMG} at (0,18) size 11x9
+ RenderBR {BR} at (11,13) size 0x18
+ RenderText {#text} at (0,27) size 163x18
+ text run at (0,27) width 107: "See, right there! "
+ text run at (106,27) width 57: "A circle!"
+ RenderBR {BR} at (162,27) size 1x18
+ RenderBR {BR} at (304,140) size 0x18
+ RenderText {#text} at (0,154) size 736x36
+ text run at (0,154) width 736: "This tests that loading a webarchive with a subresource that has an expired cache header does not attempt to hit the"
+ text run at (0,172) width 364: "network for resource, and actually uses the archived data"
diff --git a/LayoutTests/platform/mac/TestExpectations b/LayoutTests/platform/mac/TestExpectations
index bd78906e750d..90b900ff569b 100644
--- a/LayoutTests/platform/mac/TestExpectations
+++ b/LayoutTests/platform/mac/TestExpectations
@@ -276,9 +276,6 @@ webkit.org/b/103435 fast/backgrounds/background-opaque-images-over-color.html [
webkit.org/b/56685 webarchive/test-link-rel-icon.html [ Failure ]
-# The following two tests are expected to fail until <rdar://problem/34063313> is available on test systems.
-webarchive/loading/cache-expired-subresource.html [ Failure ]
-
# Quota API is not supported.
storage/storageinfo-missing-arguments.html
storage/storageinfo-no-callbacks.html
diff --git a/LayoutTests/platform/mac/fast/loader/webarchive-encoding-respected.html b/LayoutTests/platform/mac/fast/loader/webarchive-encoding-respected.html
index dad53bfa2d98..f21906dd673b 100644
--- a/LayoutTests/platform/mac/fast/loader/webarchive-encoding-respected.html
+++ b/LayoutTests/platform/mac/fast/loader/webarchive-encoding-respected.html
@@ -1,4 +1,4 @@
-<script>
+<script><!-- webkit-test-runner [ AlwaysAllowLocalWebarchive=true ] -->
if (window.testRunner) {
testRunner.dumpAsText();
testRunner.dumpChildFramesAsText();
diff --git a/LayoutTests/platform/mac/webarchive/loading/cache-expired-subresource-expected.txt b/LayoutTests/platform/mac/webarchive/loading/cache-expired-subresource-expected.txt
index f4f82962ac07..2cba2310b20f 100644
--- a/LayoutTests/platform/mac/webarchive/loading/cache-expired-subresource-expected.txt
+++ b/LayoutTests/platform/mac/webarchive/loading/cache-expired-subresource-expected.txt
@@ -9,7 +9,7 @@ frame "<!--frame1-->" - didCommitLoadForFrame
http://localhost/pink-bullet.png - willSendRequest <NSURLRequest URL http://localhost/pink-bullet.png, main document URL cache-expired-subresource.html, http method GET> redirectResponse (null)
frame "<!--frame1-->" - didFinishDocumentLoadForFrame
resources/cache-expired-subresource.webarchive - didFinishLoading
-http://localhost/pink-bullet.png - didReceiveResponse <NSURLResponse http://localhost/test.php, http status code 200>
+http://localhost/pink-bullet.png - didReceiveResponse <NSURLResponse http://localhost/pink-bullet.png, http status code 200>
http://localhost/pink-bullet.png - didFinishLoading
frame "<!--frame1-->" - didHandleOnloadEventsForFrame
main frame - didHandleOnloadEventsForFrame
@@ -28,14 +28,14 @@ layer at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 284x134
RenderText {#text} at (0,0) size 240x18
text run at (0,0) width 240: "This page has a small pink circle in it"
- RenderBR {BR} at (239,14) size 1x0
+ RenderBR {BR} at (239,0) size 1x18
RenderImage {IMG} at (0,18) size 11x9
- RenderBR {BR} at (11,27) size 0x0
+ RenderBR {BR} at (11,13) size 0x18
RenderText {#text} at (0,27) size 163x18
text run at (0,27) width 107: "See, right there! "
text run at (106,27) width 57: "A circle!"
- RenderBR {BR} at (162,41) size 1x0
- RenderBR {BR} at (304,154) size 0x0
+ RenderBR {BR} at (162,27) size 1x18
+ RenderBR {BR} at (304,140) size 0x18
RenderText {#text} at (0,154) size 736x36
text run at (0,154) width 736: "This tests that loading a webarchive with a subresource that has an expired cache header does not attempt to hit the"
text run at (0,172) width 364: "network for resource, and actually uses the archived data"
diff --git a/LayoutTests/platform/wk2/webarchive/loading/javascript-url-iframe-crash-expected.txt b/LayoutTests/platform/wk2/webarchive/loading/javascript-url-iframe-crash-expected.txt
new file mode 100644
index 000000000000..aafd7085f151
--- /dev/null
+++ b/LayoutTests/platform/wk2/webarchive/loading/javascript-url-iframe-crash-expected.txt
@@ -0,0 +1,13 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - willPerformClientRedirectToURL: resources/javascript-url-iframe-crash.webarchive
+main frame - didFinishDocumentLoadForFrame
+main frame - didFinishLoadForFrame
+main frame - didCancelClientRedirectForFrame
+frame "<!--frame1-->" - didFinishDocumentLoadForFrame
+frame "<!--frame1-->" - didHandleOnloadEventsForFrame
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+Loading this webarchive with a "non-empty javascript URL iframe" should not crash.
+
diff --git a/LayoutTests/platform/wk2/webarchive/loading/object-expected.txt b/LayoutTests/platform/wk2/webarchive/loading/object-expected.txt
new file mode 100644
index 000000000000..f446855424c5
--- /dev/null
+++ b/LayoutTests/platform/wk2/webarchive/loading/object-expected.txt
@@ -0,0 +1,16 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - willPerformClientRedirectToURL: resources/object.webarchive
+main frame - didFinishDocumentLoadForFrame
+main frame - didFinishLoadForFrame
+main frame - didCancelClientRedirectForFrame
+main frame - didFinishDocumentLoadForFrame
+frame "<!--frame1-->" - didStartProvisionalLoadForFrame
+frame "<!--frame1-->" - didCommitLoadForFrame
+frame "<!--frame1-->" - didFinishDocumentLoadForFrame
+frame "<!--frame1-->" - didHandleOnloadEventsForFrame
+main frame - didHandleOnloadEventsForFrame
+frame "<!--frame1-->" - didFinishLoadForFrame
+main frame - didFinishLoadForFrame
+Loading this webarchive with an object should not crash.
+
diff --git a/LayoutTests/platform/wk2/webarchive/loading/test-loading-top-archive-expected.txt b/LayoutTests/platform/wk2/webarchive/loading/test-loading-top-archive-expected.txt
new file mode 100644
index 000000000000..bb86d5046bb6
--- /dev/null
+++ b/LayoutTests/platform/wk2/webarchive/loading/test-loading-top-archive-expected.txt
@@ -0,0 +1,10 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - willPerformClientRedirectToURL: resources/top.webarchive
+main frame - didFinishDocumentLoadForFrame
+main frame - didFinishLoadForFrame
+main frame - didCancelClientRedirectForFrame
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+hello, world.
diff --git a/LayoutTests/platform/wk2/webarchive/loading/video-in-webarchive-expected.txt b/LayoutTests/platform/wk2/webarchive/loading/video-in-webarchive-expected.txt
index 02daa557c635..88d0906af149 100644
--- a/LayoutTests/platform/wk2/webarchive/loading/video-in-webarchive-expected.txt
+++ b/LayoutTests/platform/wk2/webarchive/loading/video-in-webarchive-expected.txt
@@ -3,9 +3,7 @@ main frame - didCommitLoadForFrame
main frame - willPerformClientRedirectToURL: resources/video-in-webarchive.webarchive
main frame - didFinishDocumentLoadForFrame
main frame - didFinishLoadForFrame
-main frame - didStartProvisionalLoadForFrame
main frame - didCancelClientRedirectForFrame
-main frame - didCommitLoadForFrame
main frame - didFinishDocumentLoadForFrame
frame "<!--frame1-->" - didStartProvisionalLoadForFrame
main frame - didHandleOnloadEventsForFrame
diff --git a/LayoutTests/webarchive/loading/cache-expired-subresource.html b/LayoutTests/webarchive/loading/cache-expired-subresource.html
index 0daf00b0e776..645ed3ae18b6 100644
--- a/LayoutTests/webarchive/loading/cache-expired-subresource.html
+++ b/LayoutTests/webarchive/loading/cache-expired-subresource.html
@@ -1,4 +1,4 @@
-<html>
+<html><!-- webkit-test-runner [ AlwaysAllowLocalWebarchive=true ] -->
<script>
if (window.testRunner) {
testRunner.dumpResourceLoadCallbacks();
diff --git a/LayoutTests/webarchive/loading/javascript-url-iframe-crash.html b/LayoutTests/webarchive/loading/javascript-url-iframe-crash.html
index 2d6d7137d504..d6fe97c4b484 100644
--- a/LayoutTests/webarchive/loading/javascript-url-iframe-crash.html
+++ b/LayoutTests/webarchive/loading/javascript-url-iframe-crash.html
@@ -1,4 +1,4 @@
-<html>
+<html><!-- webkit-test-runner [ AlwaysAllowLocalWebarchive=true ] -->
<script>
if (window.testRunner) {
testRunner.dumpAsText();
diff --git a/LayoutTests/webarchive/loading/mainresource-null-mimetype-crash.html b/LayoutTests/webarchive/loading/mainresource-null-mimetype-crash.html
index 5757fe819291..725647f9f8bd 100644
--- a/LayoutTests/webarchive/loading/mainresource-null-mimetype-crash.html
+++ b/LayoutTests/webarchive/loading/mainresource-null-mimetype-crash.html
@@ -1,4 +1,4 @@
-<html>
+<html><!-- webkit-test-runner [ AlwaysAllowLocalWebarchive=true ] -->
<script>
if (window.testRunner) {
testRunner.dumpAsText();
diff --git a/LayoutTests/webarchive/loading/missing-data.html b/LayoutTests/webarchive/loading/missing-data.html
index 6d295248c39a..c26dd6330efd 100644
--- a/LayoutTests/webarchive/loading/missing-data.html
+++ b/LayoutTests/webarchive/loading/missing-data.html
@@ -1,4 +1,4 @@
-<script>
+<script><!-- webkit-test-runner [ AlwaysAllowLocalWebarchive=true ] -->
if (window.testRunner) {
testRunner.waitUntilDone();
testRunner.dumpAsText();
... (truncated)