Add WTF::move()
[WebKit-https.git] / Source / WebCore / loader / PolicyChecker.cpp
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 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
45 #if USE(QUICK_LOOK)
46 #include "QuickLook.h"
47 #endif
48
49 #if USE(CONTENT_FILTERING)
50 #include "ContentFilter.h"
51 #endif
52
53 namespace WebCore {
54
55 PolicyChecker::PolicyChecker(Frame& frame)
56     : m_frame(frame)
57     , m_delegateIsDecidingNavigationPolicy(false)
58     , m_delegateIsHandlingUnimplementablePolicy(false)
59     , m_loadType(FrameLoadType::Standard)
60 {
61 }
62
63 void PolicyChecker::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function)
64 {
65     checkNavigationPolicy(newRequest, m_frame.loader().activeDocumentLoader(), nullptr, WTF::move(function));
66 }
67
68 void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader, PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function)
69 {
70     NavigationAction action = loader->triggeringAction();
71     if (action.isEmpty()) {
72         action = NavigationAction(request, NavigationTypeOther);
73         loader->setTriggeringAction(action);
74     }
75
76     // Don't ask more than once for the same request or if we are loading an empty URL.
77     // This avoids confusion on the part of the client.
78     if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) {
79         function(request, 0, true);
80         loader->setLastCheckedRequest(request);
81         return;
82     }
83
84     // We are always willing to show alternate content for unreachable URLs;
85     // treat it like a reload so it maintains the right state for b/f list.
86     if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) {
87         if (isBackForwardLoadType(m_loadType))
88             m_loadType = FrameLoadType::Reload;
89         function(request, 0, true);
90         return;
91     }
92
93     // If we're loading content into a subframe, check against the parent's Content Security Policy
94     // and kill the load if that check fails.
95     if (m_frame.ownerElement() && !m_frame.ownerElement()->document().contentSecurityPolicy()->allowChildFrameFromSource(request.url())) {
96         function(request, 0, false);
97         return;
98     }
99
100     loader->setLastCheckedRequest(request);
101
102     m_callback.set(request, formState.get(), WTF::move(function));
103
104 #if USE(QUICK_LOOK)
105     // Always allow QuickLook-generated URLs based on the protocol scheme.
106     if (!request.isNull() && request.url().protocolIs(QLPreviewProtocol())) {
107         continueAfterNavigationPolicy(PolicyUse);
108         return;
109     }
110 #endif
111
112 #if USE(CONTENT_FILTERING)
113     if (DocumentLoader* documentLoader = m_frame.loader().documentLoader()) {
114         if (documentLoader->handleContentFilterRequest(request)) {
115             continueAfterNavigationPolicy(PolicyIgnore);
116             return;
117         }
118     }
119 #endif
120
121     m_delegateIsDecidingNavigationPolicy = true;
122     m_frame.loader().client().dispatchDecidePolicyForNavigationAction(action, request, formState, [this](PolicyAction action) {
123         continueAfterNavigationPolicy(action);
124     });
125     m_delegateIsDecidingNavigationPolicy = false;
126 }
127
128 void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, NewWindowPolicyDecisionFunction function)
129 {
130     if (m_frame.document() && m_frame.document()->isSandboxed(SandboxPopups))
131         return continueAfterNavigationPolicy(PolicyIgnore);
132
133     if (!DOMWindow::allowPopUp(&m_frame))
134         return continueAfterNavigationPolicy(PolicyIgnore);
135
136     m_callback.set(request, formState, frameName, action, WTF::move(function));
137     m_frame.loader().client().dispatchDecidePolicyForNewWindowAction(action, request, formState, frameName, [this](PolicyAction action) {
138         continueAfterNewWindowPolicy(action);
139     });
140 }
141
142 void PolicyChecker::checkContentPolicy(const ResourceResponse& response, ContentPolicyDecisionFunction function)
143 {
144     m_callback.set(WTF::move(function));
145     m_frame.loader().client().dispatchDecidePolicyForResponse(response, m_frame.loader().activeDocumentLoader()->request(), [this](PolicyAction action) {
146         continueAfterContentPolicy(action);
147     });
148 }
149
150 void PolicyChecker::cancelCheck()
151 {
152     m_frame.loader().client().cancelPolicyCheck();
153     m_callback.clear();
154 }
155
156 void PolicyChecker::stopCheck()
157 {
158     m_frame.loader().client().cancelPolicyCheck();
159     PolicyCallback callback = m_callback;
160     m_callback.clear();
161     callback.cancel();
162 }
163
164 void PolicyChecker::cannotShowMIMEType(const ResourceResponse& response)
165 {
166     handleUnimplementablePolicy(m_frame.loader().client().cannotShowMIMETypeError(response));
167 }
168
169 void PolicyChecker::continueLoadAfterWillSubmitForm(PolicyAction)
170 {
171     // See header file for an explaination of why this function
172     // isn't like the others.
173     m_frame.loader().continueLoadAfterWillSubmitForm();
174 }
175
176 void PolicyChecker::continueAfterNavigationPolicy(PolicyAction policy)
177 {
178     PolicyCallback callback = m_callback;
179     m_callback.clear();
180
181     bool shouldContinue = policy == PolicyUse;
182
183     switch (policy) {
184         case PolicyIgnore:
185             callback.clearRequest();
186             break;
187         case PolicyDownload: {
188             ResourceRequest request = callback.request();
189             m_frame.loader().setOriginalURLForDownloadRequest(request);
190             m_frame.loader().client().startDownload(request);
191             callback.clearRequest();
192             break;
193         }
194         case PolicyUse: {
195             ResourceRequest request(callback.request());
196
197             if (!m_frame.loader().client().canHandleRequest(request)) {
198                 handleUnimplementablePolicy(m_frame.loader().client().cannotShowURLError(callback.request()));
199                 callback.clearRequest();
200                 shouldContinue = false;
201             }
202             break;
203         }
204     }
205
206     callback.call(shouldContinue);
207 }
208
209 void PolicyChecker::continueAfterNewWindowPolicy(PolicyAction policy)
210 {
211     PolicyCallback callback = m_callback;
212     m_callback.clear();
213
214     switch (policy) {
215         case PolicyIgnore:
216             callback.clearRequest();
217             break;
218         case PolicyDownload:
219             m_frame.loader().client().startDownload(callback.request());
220             callback.clearRequest();
221             break;
222         case PolicyUse:
223             break;
224     }
225
226     callback.call(policy == PolicyUse);
227 }
228
229 void PolicyChecker::continueAfterContentPolicy(PolicyAction policy)
230 {
231     PolicyCallback callback = m_callback;
232     m_callback.clear();
233     callback.call(policy);
234 }
235
236 void PolicyChecker::handleUnimplementablePolicy(const ResourceError& error)
237 {
238     m_delegateIsHandlingUnimplementablePolicy = true;
239     m_frame.loader().client().dispatchUnableToImplementPolicy(error);
240     m_delegateIsHandlingUnimplementablePolicy = false;
241 }
242
243 } // namespace WebCore