WebCore/loader/SubframeLoader.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2006, 2007, 2008, 2009, 2010 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 "Frame.h"
       
    37 #include "FrameLoaderClient.h"
       
    38 #include "HTMLAppletElement.h"
       
    39 #include "HTMLFrameElementBase.h"
       
    40 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
    41 #include "HTMLMediaElement.h"
       
    42 #endif
       
    43 #include "HTMLNames.h"
       
    44 #include "HTMLPlugInElement.h"
       
    45 #include "MIMETypeRegistry.h"
       
    46 #include "Node.h"
       
    47 #include "Page.h"
       
    48 #include "PluginData.h"
       
    49 #include "RenderEmbeddedObject.h"
       
    50 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
    51 #include "RenderVideo.h"
       
    52 #endif
       
    53 #include "RenderView.h"
       
    54 #include "Settings.h"
       
    55 #include "XSSAuditor.h"
       
    56 
       
    57 namespace WebCore {
       
    58     
       
    59 using namespace HTMLNames;
       
    60 
       
    61 SubframeLoader::SubframeLoader(Frame* frame)
       
    62     : m_containsPlugins(false)
       
    63     , m_frame(frame)
       
    64 {
       
    65 }
       
    66 
       
    67 static HTMLPlugInElement* toPlugInElement(Node* node)
       
    68 {
       
    69     if (!node)
       
    70         return 0;
       
    71 
       
    72     ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag) || node->hasTagName(appletTag));
       
    73 
       
    74     return static_cast<HTMLPlugInElement*>(node);
       
    75 }
       
    76 
       
    77 void SubframeLoader::clear()
       
    78 {
       
    79     m_containsPlugins = false;
       
    80 }
       
    81 
       
    82 bool SubframeLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
       
    83 {
       
    84     // Support for <frame src="javascript:string">
       
    85     KURL scriptURL;
       
    86     KURL url;
       
    87     if (protocolIsJavaScript(urlString)) {
       
    88         scriptURL = completeURL(urlString); // completeURL() encodes the URL.
       
    89         url = blankURL();
       
    90     } else
       
    91         url = completeURL(urlString);
       
    92 
       
    93     Frame* frame = ownerElement->contentFrame();
       
    94     if (frame)
       
    95         frame->redirectScheduler()->scheduleLocationChange(url.string(), m_frame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList, m_frame->loader()->isProcessingUserGesture());
       
    96     else
       
    97         frame = loadSubframe(ownerElement, url, frameName, m_frame->loader()->outgoingReferrer());
       
    98     
       
    99     if (!frame)
       
   100         return false;
       
   101 
       
   102     if (!scriptURL.isEmpty())
       
   103         frame->script()->executeIfJavaScriptURL(scriptURL);
       
   104 
       
   105     return true;
       
   106 }
       
   107 
       
   108 bool SubframeLoader::requestObject(RenderEmbeddedObject* renderer, const String& url, const AtomicString& frameName,
       
   109     const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
       
   110 {
       
   111     if (url.isEmpty() && mimeType.isEmpty())
       
   112         return false;
       
   113     
       
   114     if (!m_frame->script()->xssAuditor()->canLoadObject(url)) {
       
   115         // It is unsafe to honor the request for this object.
       
   116         return false;
       
   117     }
       
   118 
       
   119     KURL completedURL;
       
   120     if (!url.isEmpty())
       
   121         completedURL = completeURL(url);
       
   122 
       
   123     bool useFallback;
       
   124     if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
       
   125         Settings* settings = m_frame->settings();
       
   126         if ((!allowPlugins(AboutToInstantiatePlugin)
       
   127              // Application plugins are plugins implemented by the user agent, for example Qt plugins,
       
   128              // as opposed to third-party code such as flash. The user agent decides whether or not they are
       
   129              // permitted, rather than WebKit.
       
   130              && !MIMETypeRegistry::isApplicationPluginMIMEType(mimeType))
       
   131             || (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
       
   132             return false;
       
   133         if (m_frame->document() && m_frame->document()->securityOrigin()->isSandboxed(SandboxPlugins))
       
   134             return false;
       
   135         return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
       
   136     }
       
   137 
       
   138     ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
       
   139     HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
       
   140 
       
   141     // If the plug-in element already contains a subframe, requestFrame will re-use it. Otherwise,
       
   142     // it will create a new frame and set it as the RenderPart's widget, causing what was previously 
       
   143     // in the widget to be torn down.
       
   144     return requestFrame(element, completedURL, frameName);
       
   145 }
       
   146 
       
   147 
       
   148 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   149 PassRefPtr<Widget> FrameLoader::loadMediaPlayerProxyPlugin(Node* node, const KURL& url, 
       
   150     const Vector<String>& paramNames, const Vector<String>& paramValues)
       
   151 {
       
   152     ASSERT(node->hasTagName(videoTag) || node->hasTagName(audioTag));
       
   153 
       
   154     if (!m_frame->script()->xssAuditor()->canLoadObject(url.string()))
       
   155         return 0;
       
   156 
       
   157     KURL completedURL;
       
   158     if (!url.isEmpty())
       
   159         completedURL = completeURL(url);
       
   160 
       
   161     if (!SecurityOrigin::canLoad(completedURL, String(), frame()->document())) {
       
   162         FrameLoader::reportLocalLoadFailed(m_frame, completedURL.string());
       
   163         return 0;
       
   164     }
       
   165 
       
   166     HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node);
       
   167     RenderPart* renderer = toRenderPart(node->renderer());
       
   168     IntSize size;
       
   169 
       
   170     if (renderer)
       
   171         size = IntSize(renderer->contentWidth(), renderer->contentHeight());
       
   172     else if (mediaElement->isVideo())
       
   173         size = RenderVideo::defaultSize();
       
   174 
       
   175     m_frame->loader()->checkIfRunInsecureContent(m_frame->document()->securityOrigin(), completedURL);
       
   176 
       
   177     RefPtr<Widget> widget = m_frame->loader()->client()->createMediaPlayerProxyPlugin(size, mediaElement, completedURL,
       
   178                                          paramNames, paramValues, "application/x-media-element-proxy-plugin");
       
   179 
       
   180     if (widget && renderer) {
       
   181         renderer->setWidget(widget);
       
   182         renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
       
   183     }
       
   184     m_containsPlugIns = true;
       
   185 
       
   186     return widget ? widget.release() : 0;
       
   187 }
       
   188 
       
   189 void FrameLoader::hideMediaPlayerProxyPlugin(Widget* widget)
       
   190 {
       
   191     m_client->hideMediaPlayerProxyPlugin(widget);
       
   192 }
       
   193 
       
   194 void FrameLoader::showMediaPlayerProxyPlugin(Widget* widget)
       
   195 {
       
   196     m_client->showMediaPlayerProxyPlugin(widget);
       
   197 }
       
   198 
       
   199 #endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   200 
       
   201 PassRefPtr<Widget> SubframeLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap<String, String>& args)
       
   202 {
       
   203     String baseURLString;
       
   204     String codeBaseURLString;
       
   205     Vector<String> paramNames;
       
   206     Vector<String> paramValues;
       
   207     HashMap<String, String>::const_iterator end = args.end();
       
   208     for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
       
   209         if (equalIgnoringCase(it->first, "baseurl"))
       
   210             baseURLString = it->second;
       
   211         else if (equalIgnoringCase(it->first, "codebase"))
       
   212             codeBaseURLString = it->second;
       
   213         paramNames.append(it->first);
       
   214         paramValues.append(it->second);
       
   215     }
       
   216 
       
   217     if (!codeBaseURLString.isEmpty()) {
       
   218         KURL codeBaseURL = completeURL(codeBaseURLString);
       
   219         if (!SecurityOrigin::canLoad(codeBaseURL, String(), element->document())) {
       
   220             FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string());
       
   221             return 0;
       
   222         }
       
   223     }
       
   224 
       
   225     if (baseURLString.isEmpty())
       
   226         baseURLString = m_frame->document()->baseURL().string();
       
   227     KURL baseURL = completeURL(baseURLString);
       
   228 
       
   229     RefPtr<Widget> widget = m_frame->loader()->client()->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues);
       
   230     if (!widget)
       
   231         return 0;
       
   232 
       
   233     m_containsPlugins = true;
       
   234     return widget;
       
   235 }
       
   236 
       
   237 Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
       
   238 {
       
   239     bool allowsScrolling = true;
       
   240     int marginWidth = -1;
       
   241     int marginHeight = -1;
       
   242     if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
       
   243         HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
       
   244         allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
       
   245         marginWidth = o->getMarginWidth();
       
   246         marginHeight = o->getMarginHeight();
       
   247     }
       
   248 
       
   249     if (!SecurityOrigin::canLoad(url, referrer, 0)) {
       
   250         FrameLoader::reportLocalLoadFailed(m_frame, url.string());
       
   251         return 0;
       
   252     }
       
   253 
       
   254     bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);
       
   255     RefPtr<Frame> frame = m_frame->loader()->client()->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);
       
   256 
       
   257     if (!frame)  {
       
   258         m_frame->loader()->checkCallImplicitClose();
       
   259         return 0;
       
   260     }
       
   261     
       
   262     // All new frames will have m_isComplete set to true at this point due to synchronously loading
       
   263     // an empty document in FrameLoader::init(). But many frames will now be starting an
       
   264     // asynchronous load of url, so we set m_isComplete to false and then check if the load is
       
   265     // actually completed below. (Note that we set m_isComplete to false even for synchronous
       
   266     // loads, so that checkCompleted() below won't bail early.)
       
   267     // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
       
   268     frame->loader()->started();
       
   269    
       
   270     RenderObject* renderer = ownerElement->renderer();
       
   271     FrameView* view = frame->view();
       
   272     if (renderer && renderer->isWidget() && view)
       
   273         toRenderWidget(renderer)->setWidget(view);
       
   274     
       
   275     m_frame->loader()->checkCallImplicitClose();
       
   276     
       
   277     // Some loads are performed synchronously (e.g., about:blank and loads
       
   278     // cancelled by returning a null ResourceRequest from requestFromDelegate).
       
   279     // In these cases, the synchronous load would have finished
       
   280     // before we could connect the signals, so make sure to send the 
       
   281     // completed() signal for the child by hand and mark the load as being
       
   282     // complete.
       
   283     // FIXME: In this case the Frame will have finished loading before 
       
   284     // it's being added to the child list. It would be a good idea to
       
   285     // create the child first, then invoke the loader separately.
       
   286     if (frame->loader()->state() == FrameStateComplete && !frame->loader()->policyDocumentLoader())
       
   287         frame->loader()->checkCompleted();
       
   288 
       
   289     return frame.get();
       
   290 }
       
   291 
       
   292 bool SubframeLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
       
   293 {
       
   294     Settings* settings = m_frame->settings();
       
   295     bool allowed = m_frame->loader()->client()->allowPlugins(settings && settings->arePluginsEnabled());
       
   296     if (!allowed && reason == AboutToInstantiatePlugin)
       
   297         m_frame->loader()->client()->didNotAllowPlugins();
       
   298     return allowed;
       
   299 }
       
   300 
       
   301 
       
   302 bool SubframeLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
       
   303 {
       
   304     if (m_frame->loader()->client()->shouldUsePluginDocument(mimeType)) {
       
   305         useFallback = false;
       
   306         return true;
       
   307     }
       
   308 
       
   309     // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
       
   310     // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
       
   311     if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
       
   312         const PluginData* pluginData = m_frame->page()->pluginData();
       
   313         String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
       
   314         if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false)) 
       
   315             return true;
       
   316     }
       
   317         
       
   318     ObjectContentType objectType = m_frame->loader()->client()->objectContentType(url, mimeType);
       
   319     // If an object's content can't be handled and it has no fallback, let
       
   320     // it be handled as a plugin to show the broken plugin icon.
       
   321     useFallback = objectType == ObjectContentNone && hasFallback;
       
   322     return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
       
   323 }
       
   324   
       
   325 bool SubframeLoader::loadPlugin(RenderEmbeddedObject* renderer, const KURL& url, const String& mimeType, 
       
   326     const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
       
   327 {
       
   328     RefPtr<Widget> widget;
       
   329 
       
   330     if (renderer && !useFallback) {
       
   331         HTMLPlugInElement* element = toPlugInElement(renderer->node());
       
   332 
       
   333         if (!SecurityOrigin::canLoad(url, String(), m_frame->document())) {
       
   334             FrameLoader::reportLocalLoadFailed(m_frame, url.string());
       
   335             return false;
       
   336         }
       
   337 
       
   338         m_frame->loader()->checkIfRunInsecureContent(m_frame->document()->securityOrigin(), url);
       
   339 
       
   340         widget = m_frame->loader()->client()->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()),
       
   341                                         element, url, paramNames, paramValues, mimeType,
       
   342                                         m_frame->document()->isPluginDocument() && !m_containsPlugins);
       
   343         if (widget) {
       
   344             renderer->setWidget(widget);
       
   345             m_containsPlugins = true;
       
   346 
       
   347 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   348             renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
       
   349 #endif
       
   350         } else
       
   351             renderer->setShowsMissingPluginIndicator();
       
   352     }
       
   353 
       
   354     return widget;
       
   355 }
       
   356 
       
   357 KURL SubframeLoader::completeURL(const String& url) const
       
   358 {
       
   359     ASSERT(m_frame->document());
       
   360     return m_frame->document()->completeURL(url);
       
   361 }
       
   362 
       
   363 } // namespace WebCore