1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
5 * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2012 Apple Inc. All rights reserved.
6 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB.  If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25#include "core/html/HTMLAppletElement.h"
26
27#include "core/HTMLNames.h"
28#include "core/dom/ElementTraversal.h"
29#include "core/dom/shadow/ShadowRoot.h"
30#include "core/html/HTMLParamElement.h"
31#include "core/loader/FrameLoader.h"
32#include "core/loader/FrameLoaderClient.h"
33#include "core/frame/LocalFrame.h"
34#include "core/frame/Settings.h"
35#include "core/frame/csp/ContentSecurityPolicy.h"
36#include "core/rendering/RenderApplet.h"
37#include "core/rendering/RenderBlockFlow.h"
38#include "platform/Widget.h"
39#include "platform/weborigin/KURL.h"
40#include "platform/weborigin/SecurityOrigin.h"
41
42namespace blink {
43
44using namespace HTMLNames;
45
46HTMLAppletElement::HTMLAppletElement(Document& document, bool createdByParser)
47    : HTMLPlugInElement(appletTag, document, createdByParser, ShouldNotPreferPlugInsForImages)
48{
49    m_serviceType = "application/x-java-applet";
50}
51
52PassRefPtrWillBeRawPtr<HTMLAppletElement> HTMLAppletElement::create(Document& document, bool createdByParser)
53{
54    RefPtrWillBeRawPtr<HTMLAppletElement> element = adoptRefWillBeNoop(new HTMLAppletElement(document, createdByParser));
55    element->ensureUserAgentShadowRoot();
56    return element.release();
57}
58
59void HTMLAppletElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
60{
61    if (name == altAttr
62        || name == archiveAttr
63        || name == codeAttr
64        || name == codebaseAttr
65        || name == mayscriptAttr
66        || name == objectAttr) {
67        // Do nothing.
68        return;
69    }
70
71    HTMLPlugInElement::parseAttribute(name, value);
72}
73
74bool HTMLAppletElement::isURLAttribute(const Attribute& attribute) const
75{
76    return attribute.name() == codebaseAttr || attribute.name() == objectAttr
77        || HTMLPlugInElement::isURLAttribute(attribute);
78}
79
80bool HTMLAppletElement::hasLegalLinkAttribute(const QualifiedName& name) const
81{
82    return name == codebaseAttr || HTMLPlugInElement::hasLegalLinkAttribute(name);
83}
84
85bool HTMLAppletElement::rendererIsNeeded(const RenderStyle& style)
86{
87    if (!fastHasAttribute(codeAttr) && !hasAuthorShadowRoot())
88        return false;
89    return HTMLPlugInElement::rendererIsNeeded(style);
90}
91
92RenderObject* HTMLAppletElement::createRenderer(RenderStyle* style)
93{
94    if (!canEmbedJava() || hasAuthorShadowRoot())
95        return RenderObject::createObject(this, style);
96
97    if (usePlaceholderContent())
98        return new RenderBlockFlow(this);
99
100    return new RenderApplet(this);
101}
102
103RenderWidget* HTMLAppletElement::renderWidgetForJSBindings() const
104{
105    if (!canEmbedJava())
106        return 0;
107    return HTMLPlugInElement::renderWidgetForJSBindings();
108}
109
110RenderWidget* HTMLAppletElement::existingRenderWidget() const
111{
112    return renderPart();
113}
114
115void HTMLAppletElement::updateWidgetInternal()
116{
117    setNeedsWidgetUpdate(false);
118    // FIXME: This should ASSERT isFinishedParsingChildren() instead.
119    if (!isFinishedParsingChildren())
120        return;
121
122    RenderEmbeddedObject* renderer = renderEmbeddedObject();
123
124    LocalFrame* frame = document().frame();
125    ASSERT(frame);
126
127    Vector<String> paramNames;
128    Vector<String> paramValues;
129
130    const AtomicString& codeBase = getAttribute(codebaseAttr);
131    if (!codeBase.isNull()) {
132        KURL codeBaseURL = document().completeURL(codeBase);
133        paramNames.append("codeBase");
134        paramValues.append(codeBase.string());
135    }
136
137    const AtomicString& archive = getAttribute(archiveAttr);
138    if (!archive.isNull()) {
139        paramNames.append("archive");
140        paramValues.append(archive.string());
141    }
142
143    const AtomicString& code = getAttribute(codeAttr);
144    paramNames.append("code");
145    paramValues.append(code.string());
146
147    // If the 'codebase' attribute is set, it serves as a relative root for the file that the Java
148    // plugin will load. If the 'code' attribute is set, and the 'archive' is not set, then we need
149    // to check the url generated by resolving 'code' against 'codebase'. If the 'archive'
150    // attribute is set, then 'code' points to a class inside the archive, so we need to check the
151    // url generated by resolving 'archive' against 'codebase'.
152    KURL urlToCheck;
153    KURL rootURL = codeBase.isNull() ? document().url() : document().completeURL(codeBase);
154    if (!archive.isNull())
155        urlToCheck = KURL(rootURL, archive);
156    else if (!code.isNull())
157        urlToCheck = KURL(rootURL, code);
158    if (!canEmbedURL(urlToCheck))
159        return;
160
161    const AtomicString& name = document().isHTMLDocument() ? getNameAttribute() : getIdAttribute();
162    if (!name.isNull()) {
163        paramNames.append("name");
164        paramValues.append(name.string());
165    }
166
167    paramNames.append("baseURL");
168    KURL baseURL = document().baseURL();
169    paramValues.append(baseURL.string());
170
171    const AtomicString& mayScript = getAttribute(mayscriptAttr);
172    if (!mayScript.isNull()) {
173        paramNames.append("mayScript");
174        paramValues.append(mayScript.string());
175    }
176
177    for (HTMLParamElement* param = Traversal<HTMLParamElement>::firstChild(*this); param; param = Traversal<HTMLParamElement>::nextSibling(*param)) {
178        if (param->name().isEmpty())
179            continue;
180
181        paramNames.append(param->name());
182        paramValues.append(param->value());
183    }
184
185    RefPtr<Widget> widget;
186    if (frame->loader().allowPlugins(AboutToInstantiatePlugin))
187        widget = frame->loader().client()->createJavaAppletWidget(this, baseURL, paramNames, paramValues);
188
189    if (!widget) {
190        if (!renderer->showsUnavailablePluginIndicator())
191            renderer->setPluginUnavailabilityReason(RenderEmbeddedObject::PluginMissing);
192        return;
193    }
194    document().setContainsPlugins();
195    setWidget(widget);
196}
197
198bool HTMLAppletElement::canEmbedJava() const
199{
200    if (document().isSandboxed(SandboxPlugins))
201        return false;
202
203    Settings* settings = document().settings();
204    if (!settings)
205        return false;
206
207    if (!settings->javaEnabled())
208        return false;
209
210    return true;
211}
212
213bool HTMLAppletElement::canEmbedURL(const KURL& url) const
214{
215    DEFINE_STATIC_LOCAL(String, appletMimeType, ("application/x-java-applet"));
216
217    if (!document().securityOrigin()->canDisplay(url)) {
218        FrameLoader::reportLocalLoadFailed(document().frame(), url.string());
219        return false;
220    }
221
222    if (!document().contentSecurityPolicy()->allowObjectFromSource(url)
223        || !document().contentSecurityPolicy()->allowPluginType(appletMimeType, appletMimeType, url)) {
224        renderEmbeddedObject()->setPluginUnavailabilityReason(RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy);
225        return false;
226    }
227    return true;
228}
229
230}
231