1/*
2 * This file is part of the XSL implementation.
3 *
4 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple, Inc. All rights reserved.
5 * Copyright (C) 2005, 2006 Alexey Proskuryakov <ap@webkit.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#include "config.h"
24#include "XSLTProcessor.h"
25
26#if ENABLE(XSLT)
27
28#include "DOMImplementation.h"
29#include "CachedResourceLoader.h"
30#include "ContentSecurityPolicy.h"
31#include "DocumentFragment.h"
32#include "Frame.h"
33#include "FrameLoader.h"
34#include "FrameView.h"
35#include "SecurityOrigin.h"
36#include "SecurityOriginPolicy.h"
37#include "Text.h"
38#include "TextResourceDecoder.h"
39#include "XMLDocument.h"
40#include "markup.h"
41#include <wtf/Assertions.h>
42
43namespace WebCore {
44
45static inline void transformTextStringToXHTMLDocumentString(String& text)
46{
47 // Modify the output so that it is a well-formed XHTML document with a <pre> tag enclosing the text.
48 text.replaceWithLiteral('&', "&amp;");
49 text.replaceWithLiteral('<', "&lt;");
50 text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
51 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
52 "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
53 "<head><title/></head>\n"
54 "<body>\n"
55 "<pre>" + text + "</pre>\n"
56 "</body>\n"
57 "</html>\n";
58}
59
60XSLTProcessor::~XSLTProcessor()
61{
62 // Stylesheet shouldn't outlive its root node.
63 ASSERT(!m_stylesheetRootNode || !m_stylesheet || m_stylesheet->hasOneRef());
64}
65
66Ref<Document> XSLTProcessor::createDocumentFromSource(const String& sourceString,
67 const String& sourceEncoding, const String& sourceMIMEType, Node* sourceNode, Frame* frame)
68{
69 Ref<Document> ownerDocument(sourceNode->document());
70 bool sourceIsDocument = (sourceNode == &ownerDocument.get());
71 String documentSource = sourceString;
72
73 RefPtr<Document> result;
74 if (sourceMIMEType == "text/plain") {
75 result = XMLDocument::createXHTML(frame, sourceIsDocument ? ownerDocument->url() : URL());
76 transformTextStringToXHTMLDocumentString(documentSource);
77 } else
78 result = DOMImplementation::createDocument(sourceMIMEType, frame, sourceIsDocument ? ownerDocument->url() : URL());
79
80 // Before parsing, we need to save & detach the old document and get the new document
81 // in place. We have to do this only if we're rendering the result document.
82 if (frame) {
83 if (FrameView* view = frame->view())
84 view->clear();
85
86 if (Document* oldDocument = frame->document()) {
87 result->setTransformSourceDocument(oldDocument);
88 result->takeDOMWindowFrom(*oldDocument);
89 result->setSecurityOriginPolicy(oldDocument->securityOriginPolicy());
90 result->setCookieURL(oldDocument->cookieURL());
91 result->setFirstPartyForCookies(oldDocument->firstPartyForCookies());
92 result->setSiteForCookies(oldDocument->siteForCookies());
93 result->setStrictMixedContentMode(oldDocument->isStrictMixedContentMode());
94 result->contentSecurityPolicy()->copyStateFrom(oldDocument->contentSecurityPolicy());
95 result->contentSecurityPolicy()->copyUpgradeInsecureRequestStateFrom(*oldDocument->contentSecurityPolicy());
96 }
97
98 frame->setDocument(result.copyRef());
99 }
100
101 auto decoder = TextResourceDecoder::create(sourceMIMEType);
102 decoder->setEncoding(sourceEncoding.isEmpty() ? UTF8Encoding() : TextEncoding(sourceEncoding), TextResourceDecoder::EncodingFromXMLHeader);
103 result->setDecoder(WTFMove(decoder));
104
105 result->setContent(documentSource);
106
107 return result.releaseNonNull();
108}
109
110RefPtr<Document> XSLTProcessor::transformToDocument(Node* sourceNode)
111{
112 if (!sourceNode)
113 return nullptr;
114
115 String resultMIMEType;
116 String resultString;
117 String resultEncoding;
118 if (!transformToString(*sourceNode, resultMIMEType, resultString, resultEncoding))
119 return nullptr;
120 return createDocumentFromSource(resultString, resultEncoding, resultMIMEType, sourceNode, 0);
121}
122
123RefPtr<DocumentFragment> XSLTProcessor::transformToFragment(Node* sourceNode, Document* outputDoc)
124{
125 if (!sourceNode || !outputDoc)
126 return nullptr;
127
128 String resultMIMEType;
129 String resultString;
130 String resultEncoding;
131
132 // If the output document is HTML, default to HTML method.
133 if (outputDoc->isHTMLDocument())
134 resultMIMEType = "text/html";
135
136 if (!transformToString(*sourceNode, resultMIMEType, resultString, resultEncoding))
137 return nullptr;
138 return createFragmentForTransformToFragment(*outputDoc, resultString, resultMIMEType);
139}
140
141void XSLTProcessor::setParameter(const String& /*namespaceURI*/, const String& localName, const String& value)
142{
143 if (localName.isNull() || value.isNull())
144 return;
145
146 // FIXME: namespace support?
147 // should make a QualifiedName here but we'd have to expose the impl
148 m_parameters.set(localName, value);
149}
150
151String XSLTProcessor::getParameter(const String& /*namespaceURI*/, const String& localName) const
152{
153 if (localName.isNull())
154 return { };
155
156 // FIXME: namespace support?
157 // should make a QualifiedName here but we'd have to expose the impl
158 return m_parameters.get(localName);
159}
160
161void XSLTProcessor::removeParameter(const String& /*namespaceURI*/, const String& localName)
162{
163 if (localName.isNull())
164 return;
165
166 // FIXME: namespace support?
167 m_parameters.remove(localName);
168}
169
170void XSLTProcessor::reset()
171{
172 m_stylesheet = nullptr;
173 m_stylesheetRootNode = nullptr;
174 m_parameters.clear();
175}
176
177} // namespace WebCore
178
179#endif // ENABLE(XSLT)
180