diff options
Diffstat (limited to 'Source/WebCore/loader/PolicyChecker.cpp')
-rw-r--r-- | Source/WebCore/loader/PolicyChecker.cpp | 87 |
1 files changed, 57 insertions, 30 deletions
diff --git a/Source/WebCore/loader/PolicyChecker.cpp b/Source/WebCore/loader/PolicyChecker.cpp index 8ead413cc..a01ce2929 100644 --- a/Source/WebCore/loader/PolicyChecker.cpp +++ b/Source/WebCore/loader/PolicyChecker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006-2016 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * @@ -12,7 +12,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -31,45 +31,59 @@ #include "config.h" #include "PolicyChecker.h" +#include "ContentFilter.h" #include "ContentSecurityPolicy.h" #include "DOMWindow.h" #include "DocumentLoader.h" +#include "EventNames.h" #include "FormState.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" #include "HTMLFormElement.h" #include "HTMLFrameOwnerElement.h" -#include "SecurityOrigin.h" +#include "HTMLPlugInElement.h" #if USE(QUICK_LOOK) #include "QuickLook.h" #endif -#if USE(CONTENT_FILTERING) -#include "ContentFilter.h" -#endif - namespace WebCore { +static bool isAllowedByContentSecurityPolicy(const URL& url, const Element* ownerElement, bool didReceiveRedirectResponse) +{ + if (!ownerElement) + return true; + // Elements in user agent show tree should load whatever the embedding document policy is. + if (ownerElement->isInUserAgentShadowTree()) + return true; + + auto redirectResponseReceived = didReceiveRedirectResponse ? ContentSecurityPolicy::RedirectResponseReceived::Yes : ContentSecurityPolicy::RedirectResponseReceived::No; + + ASSERT(ownerElement->document().contentSecurityPolicy()); + if (is<HTMLPlugInElement>(ownerElement)) + return ownerElement->document().contentSecurityPolicy()->allowObjectFromSource(url, redirectResponseReceived); + return ownerElement->document().contentSecurityPolicy()->allowChildFrameFromSource(url, redirectResponseReceived); +} + PolicyChecker::PolicyChecker(Frame& frame) : m_frame(frame) , m_delegateIsDecidingNavigationPolicy(false) , m_delegateIsHandlingUnimplementablePolicy(false) - , m_loadType(FrameLoadTypeStandard) + , m_loadType(FrameLoadType::Standard) { } -void PolicyChecker::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function) +void PolicyChecker::checkNavigationPolicy(const ResourceRequest& newRequest, bool didReceiveRedirectResponse, NavigationPolicyDecisionFunction function) { - checkNavigationPolicy(newRequest, m_frame.loader().activeDocumentLoader(), nullptr, std::move(function)); + checkNavigationPolicy(newRequest, didReceiveRedirectResponse, m_frame.loader().activeDocumentLoader(), nullptr, WTFMove(function)); } -void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader, PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function) +void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, bool didReceiveRedirectResponse, DocumentLoader* loader, FormState* formState, NavigationPolicyDecisionFunction function) { NavigationAction action = loader->triggeringAction(); if (action.isEmpty()) { - action = NavigationAction(request, NavigationTypeOther); + action = NavigationAction(request, NavigationType::Other, loader->shouldOpenExternalURLsPolicyToPropagate()); loader->setTriggeringAction(action); } @@ -83,23 +97,31 @@ void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, Docume // We are always willing to show alternate content for unreachable URLs; // treat it like a reload so it maintains the right state for b/f list. - if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) { + auto& substituteData = loader->substituteData(); + if (substituteData.isValid() && !substituteData.failingURL().isEmpty()) { + bool shouldContinue = true; +#if ENABLE(CONTENT_FILTERING) + shouldContinue = ContentFilter::continueAfterSubstituteDataRequest(*m_frame.loader().activeDocumentLoader(), substituteData); +#endif if (isBackForwardLoadType(m_loadType)) - m_loadType = FrameLoadTypeReload; - function(request, 0, true); + m_loadType = FrameLoadType::Reload; + function(request, 0, shouldContinue); return; } - // If we're loading content into a subframe, check against the parent's Content Security Policy - // and kill the load if that check fails. - if (m_frame.ownerElement() && !m_frame.ownerElement()->document().contentSecurityPolicy()->allowChildFrameFromSource(request.url())) { + if (!isAllowedByContentSecurityPolicy(request.url(), m_frame.ownerElement(), didReceiveRedirectResponse)) { + if (m_frame.ownerElement()) { + // Fire a load event (even though we were blocked by CSP) as timing attacks would otherwise + // reveal that the frame was blocked. This way, it looks like any other cross-origin page load. + m_frame.ownerElement()->dispatchEvent(Event::create(eventNames().loadEvent, false, false)); + } function(request, 0, false); return; } loader->setLastCheckedRequest(request); - m_callback.set(request, formState.get(), std::move(function)); + m_callback.set(request, formState, WTFMove(function)); #if USE(QUICK_LOOK) // Always allow QuickLook-generated URLs based on the protocol scheme. @@ -109,31 +131,36 @@ void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, Docume } #endif -#if USE(CONTENT_FILTERING) - if (DocumentLoader* documentLoader = m_frame.loader().documentLoader()) { - if (documentLoader->handleContentFilterRequest(request)) { - continueAfterNavigationPolicy(PolicyIgnore); - return; - } +#if ENABLE(CONTENT_FILTERING) + if (m_contentFilterUnblockHandler.canHandleRequest(request)) { + RefPtr<Frame> frame { &m_frame }; + m_contentFilterUnblockHandler.requestUnblockAsync([frame](bool unblocked) { + if (unblocked) + frame->loader().reload(); + }); + continueAfterNavigationPolicy(PolicyIgnore); + return; } + m_contentFilterUnblockHandler = { }; #endif m_delegateIsDecidingNavigationPolicy = true; + m_suggestedFilename = action.downloadAttribute(); m_frame.loader().client().dispatchDecidePolicyForNavigationAction(action, request, formState, [this](PolicyAction action) { continueAfterNavigationPolicy(action); }); m_delegateIsDecidingNavigationPolicy = false; } -void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, NewWindowPolicyDecisionFunction function) +void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request, FormState* formState, const String& frameName, NewWindowPolicyDecisionFunction function) { if (m_frame.document() && m_frame.document()->isSandboxed(SandboxPopups)) return continueAfterNavigationPolicy(PolicyIgnore); - if (!DOMWindow::allowPopUp(&m_frame)) + if (!DOMWindow::allowPopUp(m_frame)) return continueAfterNavigationPolicy(PolicyIgnore); - m_callback.set(request, formState, frameName, action, std::move(function)); + m_callback.set(request, formState, frameName, action, WTFMove(function)); m_frame.loader().client().dispatchDecidePolicyForNewWindowAction(action, request, formState, frameName, [this](PolicyAction action) { continueAfterNewWindowPolicy(action); }); @@ -141,7 +168,7 @@ void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, const R void PolicyChecker::checkContentPolicy(const ResourceResponse& response, ContentPolicyDecisionFunction function) { - m_callback.set(std::move(function)); + m_callback.set(WTFMove(function)); m_frame.loader().client().dispatchDecidePolicyForResponse(response, m_frame.loader().activeDocumentLoader()->request(), [this](PolicyAction action) { continueAfterContentPolicy(action); }); @@ -187,7 +214,7 @@ void PolicyChecker::continueAfterNavigationPolicy(PolicyAction policy) case PolicyDownload: { ResourceRequest request = callback.request(); m_frame.loader().setOriginalURLForDownloadRequest(request); - m_frame.loader().client().startDownload(request); + m_frame.loader().client().startDownload(request, m_suggestedFilename); callback.clearRequest(); break; } |