SubframeLoader.cpp [plain text]
#include "config.h"
#include "SubframeLoader.h"
#include "ContentSecurityPolicy.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "HTMLAppletElement.h"
#include "HTMLFrameElementBase.h"
#include "HTMLNames.h"
#include "HTMLPlugInImageElement.h"
#include "MIMETypeRegistry.h"
#include "Page.h"
#include "PluginData.h"
#include "PluginDocument.h"
#include "RenderEmbeddedObject.h"
#include "RenderView.h"
#include "SecurityOrigin.h"
#include "Settings.h"
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
#include "HTMLMediaElement.h"
#include "RenderVideo.h"
#endif
namespace WebCore {
using namespace HTMLNames;
SubframeLoader::SubframeLoader(Frame* frame)
: m_containsPlugins(false)
, m_frame(frame)
{
}
void SubframeLoader::clear()
{
m_containsPlugins = false;
}
bool SubframeLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
{
KURL scriptURL;
KURL url;
if (protocolIsJavaScript(urlString)) {
scriptURL = completeURL(urlString); url = blankURL();
} else
url = completeURL(urlString);
Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList);
if (!frame)
return false;
if (!scriptURL.isEmpty())
frame->script()->executeIfJavaScriptURL(scriptURL);
return true;
}
bool SubframeLoader::resourceWillUsePlugin(const String& url, const String& mimeType, bool shouldPreferPlugInsForImages)
{
KURL completedURL;
if (!url.isEmpty())
completedURL = completeURL(url);
bool useFallback;
return shouldUsePlugin(completedURL, mimeType, shouldPreferPlugInsForImages, false, useFallback);
}
bool SubframeLoader::requestPlugin(HTMLPlugInImageElement* ownerElement, const KURL& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
{
Settings* settings = m_frame->settings();
if ((!allowPlugins(AboutToInstantiatePlugin)
&& !MIMETypeRegistry::isApplicationPluginMIMEType(mimeType))
|| (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
return false;
if (m_frame->document()) {
if (m_frame->document()->securityOrigin()->isSandboxed(SandboxPlugins))
return false;
if (!m_frame->document()->contentSecurityPolicy()->allowObjectFromSource(url))
return false;
}
ASSERT(ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag));
return loadPlugin(ownerElement, url, mimeType, paramNames, paramValues, useFallback);
}
bool SubframeLoader::requestObject(HTMLPlugInImageElement* ownerElement, const String& url, const AtomicString& frameName, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
{
if (url.isEmpty() && mimeType.isEmpty())
return false;
RenderEmbeddedObject* renderer = ownerElement->renderEmbeddedObject();
ASSERT(renderer);
if (!renderer)
return false;
KURL completedURL;
if (!url.isEmpty())
completedURL = completeURL(url);
bool useFallback;
if (shouldUsePlugin(completedURL, mimeType, ownerElement->shouldPreferPlugInsForImages(), renderer->hasFallbackContent(), useFallback))
return requestPlugin(ownerElement, completedURL, mimeType, paramNames, paramValues, useFallback);
return loadOrRedirectSubframe(ownerElement, completedURL, frameName, true, true);
}
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
PassRefPtr<Widget> SubframeLoader::loadMediaPlayerProxyPlugin(Node* node, const KURL& url,
const Vector<String>& paramNames, const Vector<String>& paramValues)
{
ASSERT(node->hasTagName(videoTag) || node->hasTagName(audioTag));
KURL completedURL;
if (!url.isEmpty())
completedURL = completeURL(url);
if (!m_frame->document()->securityOrigin()->canDisplay(completedURL)) {
FrameLoader::reportLocalLoadFailed(m_frame, completedURL.string());
return 0;
}
if (!m_frame->document()->contentSecurityPolicy()->allowMediaFromSource(completedURL))
return 0;
HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node);
RenderPart* renderer = toRenderPart(node->renderer());
IntSize size;
if (renderer)
size = IntSize(renderer->contentWidth(), renderer->contentHeight());
else if (mediaElement->isVideo())
size = RenderVideo::defaultSize();
if (!m_frame->loader()->checkIfRunInsecureContent(m_frame->document()->securityOrigin(), completedURL))
return 0;
RefPtr<Widget> widget = m_frame->loader()->client()->createMediaPlayerProxyPlugin(size, mediaElement, completedURL,
paramNames, paramValues, "application/x-media-element-proxy-plugin");
if (widget && renderer) {
renderer->setWidget(widget);
renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
}
m_containsPlugins = true;
return widget ? widget.release() : 0;
}
#endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
PassRefPtr<Widget> SubframeLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap<String, String>& args)
{
String baseURLString;
String codeBaseURLString;
Vector<String> paramNames;
Vector<String> paramValues;
HashMap<String, String>::const_iterator end = args.end();
for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
if (equalIgnoringCase(it->first, "baseurl"))
baseURLString = it->second;
else if (equalIgnoringCase(it->first, "codebase"))
codeBaseURLString = it->second;
paramNames.append(it->first);
paramValues.append(it->second);
}
if (!codeBaseURLString.isEmpty()) {
KURL codeBaseURL = completeURL(codeBaseURLString);
if (!element->document()->securityOrigin()->canDisplay(codeBaseURL)) {
FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string());
return 0;
}
if (!element->document()->contentSecurityPolicy()->allowObjectFromSource(codeBaseURL))
return 0;
}
if (baseURLString.isEmpty())
baseURLString = m_frame->document()->baseURL().string();
KURL baseURL = completeURL(baseURLString);
RefPtr<Widget> widget;
if (allowPlugins(AboutToInstantiatePlugin))
widget = m_frame->loader()->client()->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues);
if (!widget)
return 0;
m_containsPlugins = true;
return widget;
}
Frame* SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
{
Frame* frame = ownerElement->contentFrame();
if (frame)
frame->navigationScheduler()->scheduleLocationChange(m_frame->document()->securityOrigin(), url.string(), m_frame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList);
else
frame = loadSubframe(ownerElement, url, frameName, m_frame->loader()->outgoingReferrer());
return frame;
}
Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
{
bool allowsScrolling = true;
int marginWidth = -1;
int marginHeight = -1;
if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
marginWidth = o->marginWidth();
marginHeight = o->marginHeight();
}
if (!ownerElement->document()->securityOrigin()->canDisplay(url)) {
FrameLoader::reportLocalLoadFailed(m_frame, url.string());
return 0;
}
if (!ownerElement->document()->contentSecurityPolicy()->allowChildFrameFromSource(url))
return 0;
bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);
RefPtr<Frame> frame = m_frame->loader()->client()->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);
if (!frame) {
m_frame->loader()->checkCallImplicitClose();
return 0;
}
frame->loader()->started();
RenderObject* renderer = ownerElement->renderer();
FrameView* view = frame->view();
if (renderer && renderer->isWidget() && view)
toRenderWidget(renderer)->setWidget(view);
m_frame->loader()->checkCallImplicitClose();
if (frame->loader()->state() == FrameStateComplete && !frame->loader()->policyDocumentLoader())
frame->loader()->checkCompleted();
return frame.get();
}
bool SubframeLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
{
Settings* settings = m_frame->settings();
bool allowed = m_frame->loader()->client()->allowPlugins(settings && settings->arePluginsEnabled());
if (!allowed && reason == AboutToInstantiatePlugin)
m_frame->loader()->client()->didNotAllowPlugins();
return allowed;
}
bool SubframeLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool shouldPreferPlugInsForImages, bool hasFallback, bool& useFallback)
{
if (m_frame->loader()->client()->shouldUsePluginDocument(mimeType)) {
useFallback = false;
return true;
}
if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
const PluginData* pluginData = m_frame->page()->pluginData();
String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
return true;
}
ObjectContentType objectType = m_frame->loader()->client()->objectContentType(url, mimeType, shouldPreferPlugInsForImages);
useFallback = objectType == ObjectContentNone && hasFallback;
return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
}
Document* SubframeLoader::document() const
{
return m_frame->document();
}
bool SubframeLoader::loadPlugin(HTMLPlugInImageElement* pluginElement, const KURL& url, const String& mimeType,
const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
{
RenderEmbeddedObject* renderer = pluginElement->renderEmbeddedObject();
if (!renderer || useFallback)
return false;
if (!document()->securityOrigin()->canDisplay(url)) {
FrameLoader::reportLocalLoadFailed(m_frame, url.string());
return false;
}
if (!document()->contentSecurityPolicy()->allowObjectFromSource(url))
return false;
FrameLoader* frameLoader = m_frame->loader();
if (!frameLoader->checkIfRunInsecureContent(document()->securityOrigin(), url))
return false;
IntSize contentSize(renderer->contentWidth(), renderer->contentHeight());
bool loadManually = document()->isPluginDocument() && !m_containsPlugins && toPluginDocument(document())->shouldLoadPluginManually() && !document()->ownerElement();
RefPtr<Widget> widget = frameLoader->client()->createPlugin(contentSize,
pluginElement, url, paramNames, paramValues, mimeType, loadManually);
if (!widget) {
renderer->setShowsMissingPluginIndicator();
return false;
}
renderer->setWidget(widget);
m_containsPlugins = true;
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) || ENABLE(3D_PLUGIN)
pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
#endif
return true;
}
KURL SubframeLoader::completeURL(const String& url) const
{
ASSERT(m_frame->document());
return m_frame->document()->completeURL(url);
}
}