1/* 2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 4 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 16 * its contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "PolicyChecker.h" 33 34#include "ContentSecurityPolicy.h" 35#include "DOMWindow.h" 36#include "DocumentLoader.h" 37#include "FormState.h" 38#include "Frame.h" 39#include "FrameLoader.h" 40#include "FrameLoaderClient.h" 41#include "HTMLFormElement.h" 42#include "HTMLFrameOwnerElement.h" 43#include "SecurityOrigin.h" 44 45namespace WebCore { 46 47PolicyChecker::PolicyChecker(Frame* frame) 48 : m_frame(frame) 49 , m_delegateIsDecidingNavigationPolicy(false) 50 , m_delegateIsHandlingUnimplementablePolicy(false) 51 , m_loadType(FrameLoadTypeStandard) 52{ 53} 54 55void PolicyChecker::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument) 56{ 57 checkNavigationPolicy(newRequest, m_frame->loader()->activeDocumentLoader(), 0, function, argument); 58} 59 60void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader, 61 PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function, void* argument) 62{ 63 NavigationAction action = loader->triggeringAction(); 64 if (action.isEmpty()) { 65 action = NavigationAction(request, NavigationTypeOther); 66 loader->setTriggeringAction(action); 67 } 68 69 // Don't ask more than once for the same request or if we are loading an empty URL. 70 // This avoids confusion on the part of the client. 71 if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) { 72 function(argument, request, 0, true); 73 loader->setLastCheckedRequest(request); 74 return; 75 } 76 77 // We are always willing to show alternate content for unreachable URLs; 78 // treat it like a reload so it maintains the right state for b/f list. 79 if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) { 80 if (isBackForwardLoadType(m_loadType)) 81 m_loadType = FrameLoadTypeReload; 82 function(argument, request, 0, true); 83 return; 84 } 85 86 // If we're loading content into a subframe, check against the parent's Content Security Policy 87 // and kill the load if that check fails. 88 if (m_frame->ownerElement() && !m_frame->ownerElement()->document()->contentSecurityPolicy()->allowChildFrameFromSource(request.url())) { 89 function(argument, request, 0, false); 90 return; 91 } 92 93 loader->setLastCheckedRequest(request); 94 95 m_callback.set(request, formState.get(), function, argument); 96 97 m_delegateIsDecidingNavigationPolicy = true; 98 m_frame->loader()->client()->dispatchDecidePolicyForNavigationAction(&PolicyChecker::continueAfterNavigationPolicy, 99 action, request, formState); 100 m_delegateIsDecidingNavigationPolicy = false; 101} 102 103void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, NewWindowPolicyDecisionFunction function, 104 const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, void* argument) 105{ 106 if (m_frame->document() && m_frame->document()->isSandboxed(SandboxPopups)) 107 return continueAfterNavigationPolicy(PolicyIgnore); 108 109 if (!DOMWindow::allowPopUp(m_frame)) 110 return continueAfterNavigationPolicy(PolicyIgnore); 111 112 m_callback.set(request, formState, frameName, action, function, argument); 113 m_frame->loader()->client()->dispatchDecidePolicyForNewWindowAction(&PolicyChecker::continueAfterNewWindowPolicy, 114 action, request, formState, frameName); 115} 116 117void PolicyChecker::checkContentPolicy(const ResourceResponse& response, ContentPolicyDecisionFunction function, void* argument) 118{ 119 m_callback.set(function, argument); 120 m_frame->loader()->client()->dispatchDecidePolicyForResponse(&PolicyChecker::continueAfterContentPolicy, 121 response, m_frame->loader()->activeDocumentLoader()->request()); 122} 123 124void PolicyChecker::cancelCheck() 125{ 126 m_frame->loader()->client()->cancelPolicyCheck(); 127 m_callback.clear(); 128} 129 130void PolicyChecker::stopCheck() 131{ 132 m_frame->loader()->client()->cancelPolicyCheck(); 133 PolicyCallback callback = m_callback; 134 m_callback.clear(); 135 callback.cancel(); 136} 137 138void PolicyChecker::cannotShowMIMEType(const ResourceResponse& response) 139{ 140 handleUnimplementablePolicy(m_frame->loader()->client()->cannotShowMIMETypeError(response)); 141} 142 143void PolicyChecker::continueLoadAfterWillSubmitForm(PolicyAction) 144{ 145 // See header file for an explaination of why this function 146 // isn't like the others. 147 m_frame->loader()->continueLoadAfterWillSubmitForm(); 148} 149 150void PolicyChecker::continueAfterNavigationPolicy(PolicyAction policy) 151{ 152 PolicyCallback callback = m_callback; 153 m_callback.clear(); 154 155 bool shouldContinue = policy == PolicyUse; 156 157 switch (policy) { 158 case PolicyIgnore: 159 callback.clearRequest(); 160 break; 161 case PolicyDownload: { 162 ResourceRequest request = callback.request(); 163 m_frame->loader()->setOriginalURLForDownloadRequest(request); 164 m_frame->loader()->client()->startDownload(request); 165 callback.clearRequest(); 166 break; 167 } 168 case PolicyUse: { 169 ResourceRequest request(callback.request()); 170 171 if (!m_frame->loader()->client()->canHandleRequest(request)) { 172 handleUnimplementablePolicy(m_frame->loader()->client()->cannotShowURLError(callback.request())); 173 callback.clearRequest(); 174 shouldContinue = false; 175 } 176 break; 177 } 178 } 179 180 callback.call(shouldContinue); 181} 182 183void PolicyChecker::continueAfterNewWindowPolicy(PolicyAction policy) 184{ 185 PolicyCallback callback = m_callback; 186 m_callback.clear(); 187 188 switch (policy) { 189 case PolicyIgnore: 190 callback.clearRequest(); 191 break; 192 case PolicyDownload: 193 m_frame->loader()->client()->startDownload(callback.request()); 194 callback.clearRequest(); 195 break; 196 case PolicyUse: 197 break; 198 } 199 200 callback.call(policy == PolicyUse); 201} 202 203void PolicyChecker::continueAfterContentPolicy(PolicyAction policy) 204{ 205 PolicyCallback callback = m_callback; 206 m_callback.clear(); 207 callback.call(policy); 208} 209 210void PolicyChecker::handleUnimplementablePolicy(const ResourceError& error) 211{ 212 m_delegateIsHandlingUnimplementablePolicy = true; 213 m_frame->loader()->client()->dispatchUnableToImplementPolicy(error); 214 m_delegateIsHandlingUnimplementablePolicy = false; 215} 216 217} // namespace WebCore 218