Add setting to disable Java for local files even if it is otherwise enabled
[WebKit-https.git] / Source / WebCore / loader / SubframeLoader.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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  * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6  * Copyright (C) Research In Motion Limited 2009. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1.  Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer. 
14  * 2.  Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution. 
17  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
18  *     its contributors may be used to endorse or promote products derived
19  *     from this software without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34 #include "SubframeLoader.h"
35
36 #include "ContentSecurityPolicy.h"
37 #include "Frame.h"
38 #include "FrameLoaderClient.h"
39 #include "HTMLAppletElement.h"
40 #include "HTMLFrameElementBase.h"
41 #include "HTMLNames.h"
42 #include "HTMLPlugInImageElement.h"
43 #include "MIMETypeRegistry.h"
44 #include "Page.h"
45 #include "PluginData.h"
46 #include "PluginDocument.h"
47 #include "RenderEmbeddedObject.h"
48 #include "RenderView.h"
49 #include "SecurityOrigin.h"
50 #include "SecurityPolicy.h"
51 #include "Settings.h"
52
53 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
54 #include "HTMLMediaElement.h"
55 #include "RenderVideo.h"
56 #endif
57
58 namespace WebCore {
59     
60 using namespace HTMLNames;
61
62 SubframeLoader::SubframeLoader(Frame* frame)
63     : m_containsPlugins(false)
64     , m_frame(frame)
65 {
66 }
67
68 void SubframeLoader::clear()
69 {
70     m_containsPlugins = false;
71 }
72
73 bool SubframeLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
74 {
75     // Support for <frame src="javascript:string">
76     KURL scriptURL;
77     KURL url;
78     if (protocolIsJavaScript(urlString)) {
79         scriptURL = completeURL(urlString); // completeURL() encodes the URL.
80         url = blankURL();
81     } else
82         url = completeURL(urlString);
83
84     Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList);
85     if (!frame)
86         return false;
87
88     if (!scriptURL.isEmpty())
89         frame->script()->executeIfJavaScriptURL(scriptURL);
90
91     return true;
92 }
93     
94 bool SubframeLoader::resourceWillUsePlugin(const String& url, const String& mimeType, bool shouldPreferPlugInsForImages)
95 {
96     KURL completedURL;
97     if (!url.isEmpty())
98         completedURL = completeURL(url);
99
100     bool useFallback;
101     return shouldUsePlugin(completedURL, mimeType, shouldPreferPlugInsForImages, false, useFallback);
102 }
103
104 bool SubframeLoader::requestPlugin(HTMLPlugInImageElement* ownerElement, const KURL& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
105 {
106     Settings* settings = m_frame->settings();
107     if (!settings)
108         return false;
109
110     // Application plug-ins are plug-ins implemented by the user agent, for example Qt plug-ins,
111     // as opposed to third-party code such as Flash. The user agent decides whether or not they are
112     // permitted, rather than WebKit.
113     if ((!allowPlugins(AboutToInstantiatePlugin) && !MIMETypeRegistry::isApplicationPluginMIMEType(mimeType)))
114         return false;
115
116     if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) {
117         if (!settings->isJavaEnabled())
118             return false;
119         if (m_frame->document() && m_frame->document()->securityOrigin()->isLocal() && !settings->isJavaEnabledForLocalFiles())
120             return false;
121     }
122
123     if (m_frame->document()) {
124         if (m_frame->document()->isSandboxed(SandboxPlugins))
125             return false;
126         if (!m_frame->document()->contentSecurityPolicy()->allowObjectFromSource(url))
127             return false;
128     }
129
130     ASSERT(ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag));
131     return loadPlugin(ownerElement, url, mimeType, paramNames, paramValues, useFallback);
132 }
133  
134 bool SubframeLoader::requestObject(HTMLPlugInImageElement* ownerElement, const String& url, const AtomicString& frameName, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
135 {
136     if (url.isEmpty() && mimeType.isEmpty())
137         return false;
138
139     // FIXME: None of this code should use renderers!
140     RenderEmbeddedObject* renderer = ownerElement->renderEmbeddedObject();
141     ASSERT(renderer);
142     if (!renderer)
143         return false;
144
145     KURL completedURL;
146     if (!url.isEmpty())
147         completedURL = completeURL(url);
148
149     bool useFallback;
150     if (shouldUsePlugin(completedURL, mimeType, ownerElement->shouldPreferPlugInsForImages(), renderer->hasFallbackContent(), useFallback))
151         return requestPlugin(ownerElement, completedURL, mimeType, paramNames, paramValues, useFallback);
152
153     // If the plug-in element already contains a subframe, loadOrRedirectSubframe will re-use it. Otherwise,
154     // it will create a new frame and set it as the RenderPart's widget, causing what was previously 
155     // in the widget to be torn down.
156     return loadOrRedirectSubframe(ownerElement, completedURL, frameName, true, true);
157 }
158
159 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
160 PassRefPtr<Widget> SubframeLoader::loadMediaPlayerProxyPlugin(Node* node, const KURL& url,
161     const Vector<String>& paramNames, const Vector<String>& paramValues)
162 {
163     ASSERT(node->hasTagName(videoTag) || node->hasTagName(audioTag));
164
165     KURL completedURL;
166     if (!url.isEmpty())
167         completedURL = completeURL(url);
168
169     if (!m_frame->document()->securityOrigin()->canDisplay(completedURL)) {
170         FrameLoader::reportLocalLoadFailed(m_frame, completedURL.string());
171         return 0;
172     }
173
174     if (!m_frame->document()->contentSecurityPolicy()->allowMediaFromSource(completedURL))
175         return 0;
176
177     HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node);
178     RenderPart* renderer = toRenderPart(node->renderer());
179     IntSize size;
180
181     if (renderer)
182         size = roundedIntSize(LayoutSize(renderer->contentWidth(), renderer->contentHeight()));
183     else if (mediaElement->isVideo())
184         size = RenderVideo::defaultSize();
185
186     if (!m_frame->loader()->checkIfRunInsecureContent(m_frame->document()->securityOrigin(), completedURL))
187         return 0;
188
189     RefPtr<Widget> widget = m_frame->loader()->client()->createMediaPlayerProxyPlugin(size, mediaElement, completedURL,
190                                          paramNames, paramValues, "application/x-media-element-proxy-plugin");
191
192     if (widget && renderer) {
193         renderer->setWidget(widget);
194         renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
195     }
196     m_containsPlugins = true;
197
198     return widget ? widget.release() : 0;
199 }
200 #endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
201
202 PassRefPtr<Widget> SubframeLoader::createJavaAppletWidget(const LayoutSize& size, HTMLAppletElement* element, const HashMap<String, String>& args)
203 {
204     String baseURLString;
205     String codeBaseURLString;
206     Vector<String> paramNames;
207     Vector<String> paramValues;
208     HashMap<String, String>::const_iterator end = args.end();
209     for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
210         if (equalIgnoringCase(it->first, "baseurl"))
211             baseURLString = it->second;
212         else if (equalIgnoringCase(it->first, "codebase"))
213             codeBaseURLString = it->second;
214         paramNames.append(it->first);
215         paramValues.append(it->second);
216     }
217
218     if (!codeBaseURLString.isEmpty()) {
219         KURL codeBaseURL = completeURL(codeBaseURLString);
220         if (!element->document()->securityOrigin()->canDisplay(codeBaseURL)) {
221             FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string());
222             return 0;
223         }
224
225         if (!element->document()->contentSecurityPolicy()->allowObjectFromSource(codeBaseURL))
226             return 0;
227     }
228
229     if (baseURLString.isEmpty())
230         baseURLString = m_frame->document()->baseURL().string();
231     KURL baseURL = completeURL(baseURLString);
232
233     RefPtr<Widget> widget;
234     if (allowPlugins(AboutToInstantiatePlugin))
235         widget = m_frame->loader()->client()->createJavaAppletWidget(roundedIntSize(size), element, baseURL, paramNames, paramValues);
236     if (!widget)
237         return 0;
238
239     m_containsPlugins = true;
240     return widget;
241 }
242
243 Frame* SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
244 {
245     Frame* frame = ownerElement->contentFrame();
246     if (frame)
247         frame->navigationScheduler()->scheduleLocationChange(m_frame->document()->securityOrigin(), url.string(), m_frame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList);
248     else
249         frame = loadSubframe(ownerElement, url, frameName, m_frame->loader()->outgoingReferrer());
250     return frame;
251 }
252
253 Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
254 {
255     RefPtr<Frame> protect(m_frame);
256
257     bool allowsScrolling = true;
258     int marginWidth = -1;
259     int marginHeight = -1;
260     if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
261         HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
262         allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
263         marginWidth = o->marginWidth();
264         marginHeight = o->marginHeight();
265     }
266
267     if (!ownerElement->document()->securityOrigin()->canDisplay(url)) {
268         FrameLoader::reportLocalLoadFailed(m_frame, url.string());
269         return 0;
270     }
271
272     if (!ownerElement->document()->contentSecurityPolicy()->allowChildFrameFromSource(url))
273         return 0;
274
275     String referrerToUse = SecurityPolicy::generateReferrerHeader(ownerElement->document()->referrerPolicy(), url, referrer);
276     RefPtr<Frame> frame = m_frame->loader()->client()->createFrame(url, name, ownerElement, referrerToUse, allowsScrolling, marginWidth, marginHeight);
277
278     if (!frame)  {
279         m_frame->loader()->checkCallImplicitClose();
280         return 0;
281     }
282     
283     // All new frames will have m_isComplete set to true at this point due to synchronously loading
284     // an empty document in FrameLoader::init(). But many frames will now be starting an
285     // asynchronous load of url, so we set m_isComplete to false and then check if the load is
286     // actually completed below. (Note that we set m_isComplete to false even for synchronous
287     // loads, so that checkCompleted() below won't bail early.)
288     // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
289     frame->loader()->started();
290    
291     RenderObject* renderer = ownerElement->renderer();
292     FrameView* view = frame->view();
293     if (renderer && renderer->isWidget() && view)
294         toRenderWidget(renderer)->setWidget(view);
295     
296     m_frame->loader()->checkCallImplicitClose();
297     
298     // Some loads are performed synchronously (e.g., about:blank and loads
299     // cancelled by returning a null ResourceRequest from requestFromDelegate).
300     // In these cases, the synchronous load would have finished
301     // before we could connect the signals, so make sure to send the 
302     // completed() signal for the child by hand and mark the load as being
303     // complete.
304     // FIXME: In this case the Frame will have finished loading before 
305     // it's being added to the child list. It would be a good idea to
306     // create the child first, then invoke the loader separately.
307     if (frame->loader()->state() == FrameStateComplete && !frame->loader()->policyDocumentLoader())
308         frame->loader()->checkCompleted();
309
310     return frame.get();
311 }
312
313 bool SubframeLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
314 {
315     Settings* settings = m_frame->settings();
316     bool allowed = m_frame->loader()->client()->allowPlugins(settings && settings->arePluginsEnabled());
317     if (!allowed && reason == AboutToInstantiatePlugin)
318         m_frame->loader()->client()->didNotAllowPlugins();
319     return allowed;
320 }
321
322 bool SubframeLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool shouldPreferPlugInsForImages, bool hasFallback, bool& useFallback)
323 {
324     if (m_frame->loader()->client()->shouldUsePluginDocument(mimeType)) {
325         useFallback = false;
326         return true;
327     }
328
329     // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
330     // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
331     if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
332         const PluginData* pluginData = m_frame->page()->pluginData();
333         String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
334         if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false)) 
335             return true;
336     }
337         
338     ObjectContentType objectType = m_frame->loader()->client()->objectContentType(url, mimeType, shouldPreferPlugInsForImages);
339     // If an object's content can't be handled and it has no fallback, let
340     // it be handled as a plugin to show the broken plugin icon.
341     useFallback = objectType == ObjectContentNone && hasFallback;
342     return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
343 }
344
345 Document* SubframeLoader::document() const
346 {
347     return m_frame->document();
348 }
349
350 bool SubframeLoader::loadPlugin(HTMLPlugInImageElement* pluginElement, const KURL& url, const String& mimeType,
351     const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
352 {
353     RenderEmbeddedObject* renderer = pluginElement->renderEmbeddedObject();
354
355     // FIXME: This code should not depend on renderer!
356     if (!renderer || useFallback)
357         return false;
358
359     if (!document()->securityOrigin()->canDisplay(url)) {
360         FrameLoader::reportLocalLoadFailed(m_frame, url.string());
361         return false;
362     }
363
364     if (!document()->contentSecurityPolicy()->allowObjectFromSource(url))
365         return false;
366
367     FrameLoader* frameLoader = m_frame->loader();
368     if (!frameLoader->checkIfRunInsecureContent(document()->securityOrigin(), url))
369         return false;
370
371     IntSize contentSize = roundedIntSize(LayoutSize(renderer->contentWidth(), renderer->contentHeight()));
372     bool loadManually = document()->isPluginDocument() && !m_containsPlugins && toPluginDocument(document())->shouldLoadPluginManually();
373     RefPtr<Widget> widget = frameLoader->client()->createPlugin(contentSize,
374         pluginElement, url, paramNames, paramValues, mimeType, loadManually);
375
376     if (!widget) {
377         renderer->setShowsMissingPluginIndicator();
378         return false;
379     }
380
381     renderer->setWidget(widget);
382     m_containsPlugins = true;
383  
384 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) || ENABLE(3D_PLUGIN)
385     pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
386 #endif
387     return true;
388 }
389
390 KURL SubframeLoader::completeURL(const String& url) const
391 {
392     ASSERT(m_frame->document());
393     return m_frame->document()->completeURL(url);
394 }
395
396 } // namespace WebCore