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.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
34 #include "SubframeLoader.h"
36 #include "ContentSecurityPolicy.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"
45 #include "PluginData.h"
46 #include "PluginDocument.h"
47 #include "RenderEmbeddedObject.h"
48 #include "RenderView.h"
51 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
52 #include "HTMLMediaElement.h"
53 #include "RenderVideo.h"
58 using namespace HTMLNames;
60 SubframeLoader::SubframeLoader(Frame* frame)
61 : m_containsPlugins(false)
66 void SubframeLoader::clear()
68 m_containsPlugins = false;
71 bool SubframeLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
73 // Support for <frame src="javascript:string">
76 if (protocolIsJavaScript(urlString)) {
77 scriptURL = completeURL(urlString); // completeURL() encodes the URL.
80 url = completeURL(urlString);
82 Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList);
86 if (!scriptURL.isEmpty())
87 frame->script()->executeIfJavaScriptURL(scriptURL);
92 bool SubframeLoader::resourceWillUsePlugin(const String& url, const String& mimeType, bool shouldPreferPlugInsForImages)
96 completedURL = completeURL(url);
99 return shouldUsePlugin(completedURL, mimeType, shouldPreferPlugInsForImages, false, useFallback);
102 bool SubframeLoader::requestPlugin(HTMLPlugInImageElement* ownerElement, const KURL& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
104 Settings* settings = m_frame->settings();
105 if ((!allowPlugins(AboutToInstantiatePlugin)
106 // Application plug-ins are plug-ins implemented by the user agent, for example Qt plug-ins,
107 // as opposed to third-party code such as Flash. The user agent decides whether or not they are
108 // permitted, rather than WebKit.
109 && !MIMETypeRegistry::isApplicationPluginMIMEType(mimeType))
110 || (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
113 if (m_frame->document()) {
114 if (m_frame->document()->securityOrigin()->isSandboxed(SandboxPlugins))
116 if (!m_frame->document()->contentSecurityPolicy()->allowObjectFromSource(url))
120 ASSERT(ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag));
121 return loadPlugin(ownerElement, url, mimeType, paramNames, paramValues, useFallback);
124 bool SubframeLoader::requestObject(HTMLPlugInImageElement* ownerElement, const String& url, const AtomicString& frameName, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
126 if (url.isEmpty() && mimeType.isEmpty())
129 // FIXME: None of this code should use renderers!
130 RenderEmbeddedObject* renderer = ownerElement->renderEmbeddedObject();
137 completedURL = completeURL(url);
140 if (shouldUsePlugin(completedURL, mimeType, ownerElement->shouldPreferPlugInsForImages(), renderer->hasFallbackContent(), useFallback))
141 return requestPlugin(ownerElement, completedURL, mimeType, paramNames, paramValues, useFallback);
143 // If the plug-in element already contains a subframe, loadOrRedirectSubframe will re-use it. Otherwise,
144 // it will create a new frame and set it as the RenderPart's widget, causing what was previously
145 // in the widget to be torn down.
146 return loadOrRedirectSubframe(ownerElement, completedURL, frameName, true, true);
149 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
150 PassRefPtr<Widget> SubframeLoader::loadMediaPlayerProxyPlugin(Node* node, const KURL& url,
151 const Vector<String>& paramNames, const Vector<String>& paramValues)
153 ASSERT(node->hasTagName(videoTag) || node->hasTagName(audioTag));
157 completedURL = completeURL(url);
159 if (!m_frame->document()->securityOrigin()->canDisplay(completedURL)) {
160 FrameLoader::reportLocalLoadFailed(m_frame, completedURL.string());
164 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node);
165 RenderPart* renderer = toRenderPart(node->renderer());
169 size = IntSize(renderer->contentWidth(), renderer->contentHeight());
170 else if (mediaElement->isVideo())
171 size = RenderVideo::defaultSize();
173 m_frame->loader()->checkIfRunInsecureContent(m_frame->document()->securityOrigin(), completedURL);
175 RefPtr<Widget> widget = m_frame->loader()->client()->createMediaPlayerProxyPlugin(size, mediaElement, completedURL,
176 paramNames, paramValues, "application/x-media-element-proxy-plugin");
178 if (widget && renderer) {
179 renderer->setWidget(widget);
180 renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
182 m_containsPlugins = true;
184 return widget ? widget.release() : 0;
186 #endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
188 PassRefPtr<Widget> SubframeLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap<String, String>& args)
190 String baseURLString;
191 String codeBaseURLString;
192 Vector<String> paramNames;
193 Vector<String> paramValues;
194 HashMap<String, String>::const_iterator end = args.end();
195 for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
196 if (equalIgnoringCase(it->first, "baseurl"))
197 baseURLString = it->second;
198 else if (equalIgnoringCase(it->first, "codebase"))
199 codeBaseURLString = it->second;
200 paramNames.append(it->first);
201 paramValues.append(it->second);
204 if (!codeBaseURLString.isEmpty()) {
205 KURL codeBaseURL = completeURL(codeBaseURLString);
206 if (!element->document()->securityOrigin()->canDisplay(codeBaseURL)) {
207 FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string());
212 if (baseURLString.isEmpty())
213 baseURLString = m_frame->document()->baseURL().string();
214 KURL baseURL = completeURL(baseURLString);
216 RefPtr<Widget> widget;
217 if (allowPlugins(AboutToInstantiatePlugin))
218 widget = m_frame->loader()->client()->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues);
222 m_containsPlugins = true;
226 Frame* SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
228 Frame* frame = ownerElement->contentFrame();
230 frame->navigationScheduler()->scheduleLocationChange(m_frame->document()->securityOrigin(), url.string(), m_frame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList);
232 frame = loadSubframe(ownerElement, url, frameName, m_frame->loader()->outgoingReferrer());
236 Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
238 bool allowsScrolling = true;
239 int marginWidth = -1;
240 int marginHeight = -1;
241 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
242 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
243 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
244 marginWidth = o->marginWidth();
245 marginHeight = o->marginHeight();
248 if (!ownerElement->document()->securityOrigin()->canDisplay(url)) {
249 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
253 bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);
254 RefPtr<Frame> frame = m_frame->loader()->client()->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);
257 m_frame->loader()->checkCallImplicitClose();
261 // All new frames will have m_isComplete set to true at this point due to synchronously loading
262 // an empty document in FrameLoader::init(). But many frames will now be starting an
263 // asynchronous load of url, so we set m_isComplete to false and then check if the load is
264 // actually completed below. (Note that we set m_isComplete to false even for synchronous
265 // loads, so that checkCompleted() below won't bail early.)
266 // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
267 frame->loader()->started();
269 RenderObject* renderer = ownerElement->renderer();
270 FrameView* view = frame->view();
271 if (renderer && renderer->isWidget() && view)
272 toRenderWidget(renderer)->setWidget(view);
274 m_frame->loader()->checkCallImplicitClose();
276 // Some loads are performed synchronously (e.g., about:blank and loads
277 // cancelled by returning a null ResourceRequest from requestFromDelegate).
278 // In these cases, the synchronous load would have finished
279 // before we could connect the signals, so make sure to send the
280 // completed() signal for the child by hand and mark the load as being
282 // FIXME: In this case the Frame will have finished loading before
283 // it's being added to the child list. It would be a good idea to
284 // create the child first, then invoke the loader separately.
285 if (frame->loader()->state() == FrameStateComplete && !frame->loader()->policyDocumentLoader())
286 frame->loader()->checkCompleted();
291 bool SubframeLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
293 Settings* settings = m_frame->settings();
294 bool allowed = m_frame->loader()->client()->allowPlugins(settings && settings->arePluginsEnabled());
295 if (!allowed && reason == AboutToInstantiatePlugin)
296 m_frame->loader()->client()->didNotAllowPlugins();
300 bool SubframeLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool shouldPreferPlugInsForImages, bool hasFallback, bool& useFallback)
302 if (m_frame->loader()->client()->shouldUsePluginDocument(mimeType)) {
307 // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
308 // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
309 if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
310 const PluginData* pluginData = m_frame->page()->pluginData();
311 String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
312 if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
316 ObjectContentType objectType = m_frame->loader()->client()->objectContentType(url, mimeType, shouldPreferPlugInsForImages);
317 // If an object's content can't be handled and it has no fallback, let
318 // it be handled as a plugin to show the broken plugin icon.
319 useFallback = objectType == ObjectContentNone && hasFallback;
320 return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
323 Document* SubframeLoader::document() const
325 return m_frame->document();
328 bool SubframeLoader::loadPlugin(HTMLPlugInImageElement* pluginElement, const KURL& url, const String& mimeType,
329 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
331 RenderEmbeddedObject* renderer = pluginElement->renderEmbeddedObject();
333 // FIXME: This code should not depend on renderer!
334 if (!renderer || useFallback)
337 if (!document()->securityOrigin()->canDisplay(url)) {
338 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
342 FrameLoader* frameLoader = m_frame->loader();
343 frameLoader->checkIfRunInsecureContent(document()->securityOrigin(), url);
345 IntSize contentSize(renderer->contentWidth(), renderer->contentHeight());
346 bool loadManually = document()->isPluginDocument() && !m_containsPlugins && toPluginDocument(document())->shouldLoadPluginManually();
347 RefPtr<Widget> widget = frameLoader->client()->createPlugin(contentSize,
348 pluginElement, url, paramNames, paramValues, mimeType, loadManually);
351 renderer->setShowsMissingPluginIndicator();
355 renderer->setWidget(widget);
356 m_containsPlugins = true;
358 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) || ENABLE(3D_PLUGIN)
359 pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
364 KURL SubframeLoader::completeURL(const String& url) const
366 ASSERT(m_frame->document());
367 return m_frame->document()->completeURL(url);
370 } // namespace WebCore