diff options
Diffstat (limited to 'Source/WebCore/loader/appcache/ApplicationCacheHost.cpp')
-rw-r--r-- | Source/WebCore/loader/appcache/ApplicationCacheHost.cpp | 315 |
1 files changed, 190 insertions, 125 deletions
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp b/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp index 9cc3f8d85..9114699c8 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp +++ b/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2016 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,33 +29,33 @@ #include "ApplicationCache.h" #include "ApplicationCacheGroup.h" #include "ApplicationCacheResource.h" +#include "ContentSecurityPolicy.h" #include "DocumentLoader.h" #include "DOMApplicationCache.h" +#include "EventNames.h" +#include "FileSystem.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" #include "InspectorInstrumentation.h" +#include "MainFrame.h" +#include "Page.h" #include "ProgressEvent.h" #include "ResourceHandle.h" -#include "ResourceLoader.h" #include "ResourceRequest.h" #include "Settings.h" +#include "SubresourceLoader.h" namespace WebCore { -ApplicationCacheHost::ApplicationCacheHost(DocumentLoader* documentLoader) - : m_domApplicationCache(0) - , m_documentLoader(documentLoader) - , m_defersEvents(true) - , m_candidateApplicationCacheGroup(0) +ApplicationCacheHost::ApplicationCacheHost(DocumentLoader& documentLoader) + : m_documentLoader(documentLoader) { - ASSERT(m_documentLoader); } ApplicationCacheHost::~ApplicationCacheHost() { ASSERT(!m_applicationCache || !m_candidateApplicationCacheGroup || m_applicationCache->group() == m_candidateApplicationCacheGroup); - if (m_applicationCache) m_applicationCache->group()->disassociateDocumentLoader(m_documentLoader); else if (m_candidateApplicationCacheGroup) @@ -64,31 +64,41 @@ ApplicationCacheHost::~ApplicationCacheHost() void ApplicationCacheHost::selectCacheWithoutManifest() { - ApplicationCacheGroup::selectCacheWithoutManifestURL(m_documentLoader->frame()); + ASSERT(m_documentLoader.frame()); + ApplicationCacheGroup::selectCacheWithoutManifestURL(*m_documentLoader.frame()); } void ApplicationCacheHost::selectCacheWithManifest(const URL& manifestURL) { - ApplicationCacheGroup::selectCache(m_documentLoader->frame(), manifestURL); + ASSERT(m_documentLoader.frame()); + ApplicationCacheGroup::selectCache(*m_documentLoader.frame(), manifestURL); } void ApplicationCacheHost::maybeLoadMainResource(ResourceRequest& request, SubstituteData& substituteData) { // Check if this request should be loaded from the application cache - if (!substituteData.isValid() && isApplicationCacheEnabled()) { + if (!substituteData.isValid() && isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) { ASSERT(!m_mainResourceApplicationCache); - m_mainResourceApplicationCache = ApplicationCacheGroup::cacheForMainRequest(request, m_documentLoader); + m_mainResourceApplicationCache = ApplicationCacheGroup::cacheForMainRequest(request, &m_documentLoader); if (m_mainResourceApplicationCache) { // Get the resource from the application cache. By definition, cacheForMainRequest() returns a cache that contains the resource. ApplicationCacheResource* resource = m_mainResourceApplicationCache->resourceForRequest(request); - substituteData = SubstituteData(resource->data(), - resource->response().mimeType(), - resource->response().textEncodingName(), - URL(), + + // ApplicationCache resources have fragment identifiers stripped off of their URLs, + // but we'll need to restore that for the SubstituteData. + ResourceResponse responseToUse = resource->response(); + if (request.url().hasFragmentIdentifier()) { + URL url = responseToUse.url(); + url.setFragmentIdentifier(request.url().fragmentIdentifier()); + responseToUse.setURL(url); + } + + substituteData = SubstituteData(&resource->data(), URL(), - SubstituteData::ShouldRevealToSessionHistory); + responseToUse, + SubstituteData::SessionHistoryVisibility::Visible); } } } @@ -103,10 +113,10 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainResponse(const ResourceReques { if (r.httpStatusCode() / 100 == 4 || r.httpStatusCode() / 100 == 5) { ASSERT(!m_mainResourceApplicationCache); - if (isApplicationCacheEnabled()) { - m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, documentLoader()); + if (isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) { + m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, &m_documentLoader); - if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get())) + if (scheduleLoadFallbackResourceFromApplicationCache(m_documentLoader.mainResourceLoader(), m_mainResourceApplicationCache.get())) return true; } } @@ -117,10 +127,10 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainError(const ResourceRequest& { if (!error.isCancellation()) { ASSERT(!m_mainResourceApplicationCache); - if (isApplicationCacheEnabled()) { - m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, m_documentLoader); + if (isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) { + m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, &m_documentLoader); - if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get())) + if (scheduleLoadFallbackResourceFromApplicationCache(m_documentLoader.mainResourceLoader(), m_mainResourceApplicationCache.get())) return true; } } @@ -129,12 +139,11 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainError(const ResourceRequest& void ApplicationCacheHost::mainResourceDataReceived(const char*, int, long long, bool) { - // This method is here to facilitate alternate implemetations of this interface by the host browser. } void ApplicationCacheHost::failedLoadingMainResource() { - ApplicationCacheGroup* group = m_candidateApplicationCacheGroup; + auto* group = m_candidateApplicationCacheGroup; if (!group && m_applicationCache) { if (mainResourceApplicationCache()) { // Even when the main resource is being loaded from an application cache, loading can fail if aborted. @@ -149,7 +158,7 @@ void ApplicationCacheHost::failedLoadingMainResource() void ApplicationCacheHost::finishedLoadingMainResource() { - ApplicationCacheGroup* group = candidateApplicationCacheGroup(); + auto* group = candidateApplicationCacheGroup(); if (!group && applicationCache() && !mainResourceApplicationCache()) group = applicationCache()->group(); @@ -157,9 +166,9 @@ void ApplicationCacheHost::finishedLoadingMainResource() group->finishedLoadingMainResource(m_documentLoader); } -bool ApplicationCacheHost::maybeLoadResource(ResourceLoader* loader, ResourceRequest& request, const URL& originalURL) +bool ApplicationCacheHost::maybeLoadResource(ResourceLoader& loader, const ResourceRequest& request, const URL& originalURL) { - if (!isApplicationCacheEnabled()) + if (!isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) return false; if (request.url() != originalURL) @@ -168,33 +177,33 @@ bool ApplicationCacheHost::maybeLoadResource(ResourceLoader* loader, ResourceReq ApplicationCacheResource* resource; if (!shouldLoadResourceFromApplicationCache(request, resource)) return false; - - m_documentLoader->m_pendingSubstituteResources.set(loader, resource); - m_documentLoader->deliverSubstituteResourcesAfterDelay(); - + + m_documentLoader.scheduleSubstituteResourceLoad(loader, *resource); return true; } bool ApplicationCacheHost::maybeLoadFallbackForRedirect(ResourceLoader* resourceLoader, ResourceRequest& request, const ResourceResponse& redirectResponse) { - if (!redirectResponse.isNull() && !protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) + if (!redirectResponse.isNull() && !protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) { if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader)) return true; + } return false; } bool ApplicationCacheHost::maybeLoadFallbackForResponse(ResourceLoader* resourceLoader, const ResourceResponse& response) { - if (response.httpStatusCode() / 100 == 4 || response.httpStatusCode() / 100 == 5) + if (response.httpStatusCode() / 100 == 4 || response.httpStatusCode() / 100 == 5) { if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader)) return true; + } return false; } bool ApplicationCacheHost::maybeLoadFallbackForError(ResourceLoader* resourceLoader, const ResourceError& error) { if (!error.isCancellation()) { - if (resourceLoader == m_documentLoader->mainResourceLoader()) + if (resourceLoader == m_documentLoader.mainResourceLoader()) return maybeLoadFallbackForMainError(resourceLoader->request(), error); if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader)) return true; @@ -202,22 +211,51 @@ bool ApplicationCacheHost::maybeLoadFallbackForError(ResourceLoader* resourceLoa return false; } -bool ApplicationCacheHost::maybeLoadSynchronously(ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data) +URL ApplicationCacheHost::createFileURL(const String& path) +{ + // FIXME: Can we just use fileURLWithFileSystemPath instead? + + // fileURLWithFileSystemPath function is not suitable because URL::setPath uses encodeWithURLEscapeSequences, which it notes + // does not correctly escape '#' and '?'. This function works for our purposes because + // app cache media files are always created with encodeForFileName(createCanonicalUUIDString()). + +#if USE(CF) && PLATFORM(WIN) + URL url(adoptCF(CFURLCreateWithFileSystemPath(0, path.createCFString().get(), kCFURLWindowsPathStyle, false)).get()); +#else + URL url; + url.setProtocol(ASCIILiteral("file")); + url.setPath(path); +#endif + return url; +} + +static inline RefPtr<SharedBuffer> bufferFromResource(ApplicationCacheResource& resource) +{ + // FIXME: Clients probably do not need a copy of the SharedBuffer. + // Remove the call to copy() once we ensure SharedBuffer will not be modified. + if (resource.path().isEmpty()) + return resource.data().copy(); + return SharedBuffer::createWithContentsOfFile(resource.path()); +} + +bool ApplicationCacheHost::maybeLoadSynchronously(ResourceRequest& request, ResourceError& error, ResourceResponse& response, RefPtr<SharedBuffer>& data) { ApplicationCacheResource* resource; - if (shouldLoadResourceFromApplicationCache(request, resource)) { - if (resource) { - response = resource->response(); - data.append(resource->data()->data(), resource->data()->size()); - } else { - error = documentLoader()->frameLoader()->client().cannotShowURLError(request); - } + if (!shouldLoadResourceFromApplicationCache(request, resource)) + return false; + + auto responseData = resource ? bufferFromResource(*resource) : nullptr; + if (!responseData) { + error = m_documentLoader.frameLoader()->client().cannotShowURLError(request); return true; } - return false; + + response = resource->response(); + data = WTFMove(responseData); + return true; } -void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data) +void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, RefPtr<SharedBuffer>& data) { // If normal loading results in a redirect to a resource with another origin (indicative of a captive portal), or a 4xx or 5xx status code or equivalent, // or if there were network errors (but not if the user canceled the download), then instead get, from the cache, the resource of the fallback entry @@ -228,8 +266,9 @@ void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest& ApplicationCacheResource* resource; if (getApplicationCacheFallbackResource(request, resource)) { response = resource->response(); - data.clear(); - data.append(resource->data()->data(), resource->data()->size()); + // FIXME: Clients proably do not need a copy of the SharedBuffer. + // Remove the call to copy() once we ensure SharedBuffer will not be modified. + data = resource->data().copy(); } } } @@ -245,20 +284,21 @@ void ApplicationCacheHost::setDOMApplicationCache(DOMApplicationCache* domApplic m_domApplicationCache = domApplicationCache; } -void ApplicationCacheHost::notifyDOMApplicationCache(EventID id, int total, int done) +void ApplicationCacheHost::notifyDOMApplicationCache(const AtomicString& eventType, int total, int done) { - if (id != PROGRESS_EVENT) - InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader->frame()); + if (eventType != eventNames().progressEvent) + InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader.frame()); if (m_defersEvents) { // Event dispatching is deferred until document.onload has fired. - m_deferredEvents.append(DeferredEvent(id, total, done)); + m_deferredEvents.append({ eventType, total, done }); return; } - dispatchDOMEvent(id, total, done); + + dispatchDOMEvent(eventType, total, done); } -void ApplicationCacheHost::stopLoadingInFrame(Frame* frame) +void ApplicationCacheHost::stopLoadingInFrame(Frame& frame) { ASSERT(!m_applicationCache || !m_candidateApplicationCacheGroup || m_applicationCache->group() == m_candidateApplicationCacheGroup); @@ -270,56 +310,69 @@ void ApplicationCacheHost::stopLoadingInFrame(Frame* frame) void ApplicationCacheHost::stopDeferringEvents() { - RefPtr<DocumentLoader> protect(documentLoader()); - for (unsigned i = 0; i < m_deferredEvents.size(); ++i) { - const DeferredEvent& deferred = m_deferredEvents[i]; - dispatchDOMEvent(deferred.eventID, deferred.progressTotal, deferred.progressDone); + Ref<DocumentLoader> protect(m_documentLoader); + + // Note, do not cache the size in a local variable. + // This code needs to properly handle the case where more events are added to + // m_deferredEvents while iterating it. This is why we don't use a modern for loop. + for (size_t i = 0; i < m_deferredEvents.size(); ++i) { + auto& event = m_deferredEvents[i]; + dispatchDOMEvent(event.eventType, event.progressTotal, event.progressDone); } + m_deferredEvents.clear(); m_defersEvents = false; } -#if ENABLE(INSPECTOR) -void ApplicationCacheHost::fillResourceList(ResourceInfoList* resources) +Vector<ApplicationCacheHost::ResourceInfo> ApplicationCacheHost::resourceList() { - ApplicationCache* cache = applicationCache(); + Vector<ResourceInfo> result; + + auto* cache = applicationCache(); if (!cache || !cache->isComplete()) - return; - - for (const auto& urlAndResource : *cache) { - RefPtr<ApplicationCacheResource> resource = urlAndResource.value; - unsigned type = resource->type(); - bool isMaster = type & ApplicationCacheResource::Master; + return result; + + result.reserveInitialCapacity(cache->resources().size()); + + for (auto& urlAndResource : cache->resources()) { + ASSERT(urlAndResource.value); + auto& resource = *urlAndResource.value; + + unsigned type = resource.type(); + bool isMaster = type & ApplicationCacheResource::Master; bool isManifest = type & ApplicationCacheResource::Manifest; bool isExplicit = type & ApplicationCacheResource::Explicit; - bool isForeign = type & ApplicationCacheResource::Foreign; + bool isForeign = type & ApplicationCacheResource::Foreign; bool isFallback = type & ApplicationCacheResource::Fallback; - resources->append(ResourceInfo(resource->url(), isMaster, isManifest, isFallback, isForeign, isExplicit, resource->estimatedSizeInStorage())); + + result.uncheckedAppend({ resource.url(), isMaster, isManifest, isFallback, isForeign, isExplicit, resource.estimatedSizeInStorage() }); } + + return result; } - + ApplicationCacheHost::CacheInfo ApplicationCacheHost::applicationCacheInfo() { - ApplicationCache* cache = applicationCache(); + auto* cache = applicationCache(); if (!cache || !cache->isComplete()) - return CacheInfo(URL(), 0, 0, 0); - + return { { }, 0, 0, 0 }; + // FIXME: Add "Creation Time" and "Update Time" to Application Caches. - return CacheInfo(cache->manifestResource()->url(), 0, 0, cache->estimatedSizeInStorage()); + return { cache->manifestResource()->url(), 0, 0, cache->estimatedSizeInStorage() }; } -#endif -void ApplicationCacheHost::dispatchDOMEvent(EventID id, int total, int done) +static Ref<Event> createApplicationCacheEvent(const AtomicString& eventType, int total, int done) { - if (m_domApplicationCache) { - const AtomicString& eventType = DOMApplicationCache::toEventType(id); - RefPtr<Event> event; - if (id == PROGRESS_EVENT) - event = ProgressEvent::create(eventType, true, done, total); - else - event = Event::create(eventType, false, false); - m_domApplicationCache->dispatchEvent(event, ASSERT_NO_EXCEPTION); - } + if (eventType == eventNames().progressEvent) + return ProgressEvent::create(eventType, true, done, total); + return Event::create(eventType, false, false); +} + +void ApplicationCacheHost::dispatchDOMEvent(const AtomicString& eventType, int total, int done) +{ + if (!m_domApplicationCache) + return; + m_domApplicationCache->dispatchEvent(createApplicationCacheEvent(eventType, total, done)); } void ApplicationCacheHost::setCandidateApplicationCacheGroup(ApplicationCacheGroup* group) @@ -328,25 +381,30 @@ void ApplicationCacheHost::setCandidateApplicationCacheGroup(ApplicationCacheGro m_candidateApplicationCacheGroup = group; } -void ApplicationCacheHost::setApplicationCache(PassRefPtr<ApplicationCache> applicationCache) +void ApplicationCacheHost::setApplicationCache(RefPtr<ApplicationCache>&& applicationCache) { if (m_candidateApplicationCacheGroup) { ASSERT(!m_applicationCache); - m_candidateApplicationCacheGroup = 0; + m_candidateApplicationCacheGroup = nullptr; } - - m_applicationCache = applicationCache; + m_applicationCache = WTFMove(applicationCache); } -bool ApplicationCacheHost::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource) +bool ApplicationCacheHost::shouldLoadResourceFromApplicationCache(const ResourceRequest& originalRequest, ApplicationCacheResource*& resource) { - ApplicationCache* cache = applicationCache(); + auto* cache = applicationCache(); if (!cache || !cache->isComplete()) return false; + ResourceRequest request(originalRequest); + if (auto* loaderFrame = m_documentLoader.frame()) { + if (auto* document = loaderFrame->document()) + document->contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(request, ContentSecurityPolicy::InsecureRequestType::Load); + } + // If the resource is not to be fetched using the HTTP GET mechanism or equivalent, or if its URL has a different // <scheme> component than the application cache's manifest, then fetch the resource normally. - if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request) || !equalIgnoringCase(request.url().protocol(), cache->manifestResource()->url().protocol())) + if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request) || !equalIgnoringASCIICase(request.url().protocol(), cache->manifestResource()->url().protocol())) return false; // If the resource's URL is an master entry, the manifest, an explicit entry, or a fallback entry @@ -385,45 +443,40 @@ bool ApplicationCacheHost::getApplicationCacheFallbackResource(const ResourceReq resource = cache->resourceForURL(fallbackURL); ASSERT(resource); - return true; } bool ApplicationCacheHost::scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader* loader, ApplicationCache* cache) { - if (!isApplicationCacheEnabled()) + if (!isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(loader->request())) return false; ApplicationCacheResource* resource; if (!getApplicationCacheFallbackResource(loader->request(), resource, cache)) return false; - m_documentLoader->m_pendingSubstituteResources.set(loader, resource); - m_documentLoader->deliverSubstituteResourcesAfterDelay(); - - loader->handle()->cancel(); - + loader->willSwitchToSubstituteResource(); + m_documentLoader.scheduleSubstituteResourceLoad(*loader, *resource); return true; } ApplicationCacheHost::Status ApplicationCacheHost::status() const { - ApplicationCache* cache = applicationCache(); + auto* cache = applicationCache(); if (!cache) return UNCACHED; switch (cache->group()->updateStatus()) { - case ApplicationCacheGroup::Checking: - return CHECKING; - case ApplicationCacheGroup::Downloading: - return DOWNLOADING; - case ApplicationCacheGroup::Idle: { - if (cache->group()->isObsolete()) - return OBSOLETE; - if (cache != cache->group()->newestCache()) - return UPDATEREADY; - return IDLE; - } + case ApplicationCacheGroup::Checking: + return CHECKING; + case ApplicationCacheGroup::Downloading: + return DOWNLOADING; + case ApplicationCacheGroup::Idle: + if (cache->group()->isObsolete()) + return OBSOLETE; + if (cache != cache->group()->newestCache()) + return UPDATEREADY; + return IDLE; } ASSERT_NOT_REACHED(); @@ -432,16 +485,19 @@ ApplicationCacheHost::Status ApplicationCacheHost::status() const bool ApplicationCacheHost::update() { - ApplicationCache* cache = applicationCache(); + auto* cache = applicationCache(); if (!cache) return false; - cache->group()->update(m_documentLoader->frame(), ApplicationCacheUpdateWithoutBrowsingContext); + auto* frame = m_documentLoader.frame(); + if (!frame) + return false; + cache->group()->update(*frame, ApplicationCacheUpdateWithoutBrowsingContext); return true; } bool ApplicationCacheHost::swapCache() { - ApplicationCache* cache = applicationCache(); + auto* cache = applicationCache(); if (!cache) return false; @@ -452,31 +508,40 @@ bool ApplicationCacheHost::swapCache() } // If there is no newer cache, raise an INVALID_STATE_ERR exception. - ApplicationCache* newestCache = cache->group()->newestCache(); + auto* newestCache = cache->group()->newestCache(); if (cache == newestCache) return false; ASSERT(cache->group() == newestCache->group()); setApplicationCache(newestCache); - InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader->frame()); + InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader.frame()); return true; } void ApplicationCacheHost::abort() { - ApplicationCacheGroup* cacheGroup = candidateApplicationCacheGroup(); - if (cacheGroup) - cacheGroup->abort(m_documentLoader->frame()); - else { - ApplicationCache* cache = applicationCache(); - if (cache) - cache->group()->abort(m_documentLoader->frame()); - } + auto* frame = m_documentLoader.frame(); + if (!frame) + return; + if (auto* cacheGroup = candidateApplicationCacheGroup()) + cacheGroup->abort(*frame); + else if (auto* cache = applicationCache()) + cache->group()->abort(*frame); } bool ApplicationCacheHost::isApplicationCacheEnabled() { - return m_documentLoader->frame() && m_documentLoader->frame()->settings().offlineWebApplicationCacheEnabled(); + return m_documentLoader.frame() && m_documentLoader.frame()->settings().offlineWebApplicationCacheEnabled() && !m_documentLoader.frame()->page()->usesEphemeralSession(); +} + +bool ApplicationCacheHost::isApplicationCacheBlockedForRequest(const ResourceRequest& request) +{ + auto* frame = m_documentLoader.frame(); + if (!frame) + return false; + if (frame->isMainFrame()) + return false; + return !SecurityOrigin::create(request.url())->canAccessApplicationCache(frame->document()->topOrigin()); } } // namespace WebCore |