CachedResourceRequest constructor should be made more efficient
[WebKit-https.git] / Source / WebCore / dom / ProcessingInstruction.cpp
1 /*
2  * Copyright (C) 2000 Peter Kelly (pmk@post.com)
3  * Copyright (C) 2006, 2008, 2009 Apple Inc. All rights reserved.
4  * Copyright (C) 2013 Samsung Electronics. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "ProcessingInstruction.h"
24
25 #include "CSSStyleSheet.h"
26 #include "CachedCSSStyleSheet.h"
27 #include "CachedResourceLoader.h"
28 #include "CachedResourceRequest.h"
29 #include "CachedXSLStyleSheet.h"
30 #include "Document.h"
31 #include "ExceptionCode.h"
32 #include "Frame.h"
33 #include "FrameLoader.h"
34 #include "XSLStyleSheet.h"
35 #include "XMLDocumentParser.h" // for parseAttributes()
36 #include "MediaList.h"
37 #include "StyleScope.h"
38 #include "StyleSheetContents.h"
39
40 namespace WebCore {
41
42 inline ProcessingInstruction::ProcessingInstruction(Document& document, const String& target, const String& data)
43     : CharacterData(document, data, CreateOther)
44     , m_target(target)
45 {
46 }
47
48 Ref<ProcessingInstruction> ProcessingInstruction::create(Document& document, const String& target, const String& data)
49 {
50     return adoptRef(*new ProcessingInstruction(document, target, data));
51 }
52
53 ProcessingInstruction::~ProcessingInstruction()
54 {
55     if (m_sheet)
56         m_sheet->clearOwnerNode();
57
58     if (m_cachedSheet)
59         m_cachedSheet->removeClient(*this);
60
61     if (inDocument())
62         document().styleScope().removeStyleSheetCandidateNode(*this);
63 }
64
65 String ProcessingInstruction::nodeName() const
66 {
67     return m_target;
68 }
69
70 Node::NodeType ProcessingInstruction::nodeType() const
71 {
72     return PROCESSING_INSTRUCTION_NODE;
73 }
74
75 Ref<Node> ProcessingInstruction::cloneNodeInternal(Document& targetDocument, CloningOperation)
76 {
77     // FIXME: Is it a problem that this does not copy m_localHref?
78     // What about other data members?
79     return create(targetDocument, m_target, data());
80 }
81
82 void ProcessingInstruction::checkStyleSheet()
83 {
84     if (m_target == "xml-stylesheet" && document().frame() && parentNode() == &document()) {
85         // see http://www.w3.org/TR/xml-stylesheet/
86         // ### support stylesheet included in a fragment of this (or another) document
87         // ### make sure this gets called when adding from javascript
88         bool attrsOk;
89         const HashMap<String, String> attrs = parseAttributes(data(), attrsOk);
90         if (!attrsOk)
91             return;
92         HashMap<String, String>::const_iterator i = attrs.find("type");
93         String type;
94         if (i != attrs.end())
95             type = i->value;
96
97         m_isCSS = type.isEmpty() || type == "text/css";
98 #if ENABLE(XSLT)
99         m_isXSL = (type == "text/xml" || type == "text/xsl" || type == "application/xml" ||
100                    type == "application/xhtml+xml" || type == "application/rss+xml" || type == "application/atom+xml");
101         if (!m_isCSS && !m_isXSL)
102 #else
103         if (!m_isCSS)
104 #endif
105             return;
106
107         String href = attrs.get("href");
108         String alternate = attrs.get("alternate");
109         m_alternate = alternate == "yes";
110         m_title = attrs.get("title");
111         m_media = attrs.get("media");
112
113         if (m_alternate && m_title.isEmpty())
114             return;
115
116         if (href.length() > 1 && href[0] == '#') {
117             m_localHref = href.substring(1);
118 #if ENABLE(XSLT)
119             // We need to make a synthetic XSLStyleSheet that is embedded.  It needs to be able
120             // to kick off import/include loads that can hang off some parent sheet.
121             if (m_isXSL) {
122                 URL finalURL(ParsedURLString, m_localHref);
123                 m_sheet = XSLStyleSheet::createEmbedded(this, finalURL);
124                 m_loading = false;
125             }
126 #endif
127         } else {
128             if (m_cachedSheet) {
129                 m_cachedSheet->removeClient(*this);
130                 m_cachedSheet = nullptr;
131             }
132
133             String url = document().completeURL(href).string();
134             if (!dispatchBeforeLoadEvent(url))
135                 return;
136
137             m_loading = true;
138             document().styleScope().addPendingSheet();
139
140 #if ENABLE(XSLT)
141             if (m_isXSL) {
142                 auto options = CachedResourceLoader::defaultCachedResourceOptions();
143                 options.mode = FetchOptions::Mode::SameOrigin;
144                 m_cachedSheet = document().cachedResourceLoader().requestXSLStyleSheet({ResourceRequest(document().completeURL(href)), options});
145             } else
146 #endif
147             {
148                 String charset = attrs.get("charset");
149                 CachedResourceRequest request(document().completeURL(href), CachedResourceLoader::defaultCachedResourceOptions(), Nullopt, charset.isEmpty() ? document().charset() : WTFMove(charset));
150
151                 m_cachedSheet = document().cachedResourceLoader().requestCSSStyleSheet(WTFMove(request));
152             }
153             if (m_cachedSheet)
154                 m_cachedSheet->addClient(*this);
155             else {
156                 // The request may have been denied if (for example) the stylesheet is local and the document is remote.
157                 m_loading = false;
158                 document().styleScope().removePendingSheet();
159             }
160         }
161     }
162 }
163
164 bool ProcessingInstruction::isLoading() const
165 {
166     if (m_loading)
167         return true;
168     if (!m_sheet)
169         return false;
170     return m_sheet->isLoading();
171 }
172
173 bool ProcessingInstruction::sheetLoaded()
174 {
175     if (!isLoading()) {
176         document().styleScope().removePendingSheet();
177         return true;
178     }
179     return false;
180 }
181
182 void ProcessingInstruction::setCSSStyleSheet(const String& href, const URL& baseURL, const String& charset, const CachedCSSStyleSheet* sheet)
183 {
184     if (!inDocument()) {
185         ASSERT(!m_sheet);
186         return;
187     }
188
189     ASSERT(m_isCSS);
190     CSSParserContext parserContext(document(), baseURL, charset);
191
192     auto cssSheet = CSSStyleSheet::create(StyleSheetContents::create(href, parserContext), *this);
193     cssSheet.get().setDisabled(m_alternate);
194     cssSheet.get().setTitle(m_title);
195     cssSheet.get().setMediaQueries(MediaQuerySet::create(m_media));
196
197     m_sheet = WTFMove(cssSheet);
198
199     // We don't need the cross-origin security check here because we are
200     // getting the sheet text in "strict" mode. This enforces a valid CSS MIME
201     // type.
202     parseStyleSheet(sheet->sheetText());
203 }
204
205 #if ENABLE(XSLT)
206 void ProcessingInstruction::setXSLStyleSheet(const String& href, const URL& baseURL, const String& sheet)
207 {
208     ASSERT(m_isXSL);
209     m_sheet = XSLStyleSheet::create(this, href, baseURL);
210     Ref<Document> protect(document());
211     parseStyleSheet(sheet);
212 }
213 #endif
214
215 void ProcessingInstruction::parseStyleSheet(const String& sheet)
216 {
217     if (m_isCSS)
218         downcast<CSSStyleSheet>(*m_sheet).contents().parseString(sheet);
219 #if ENABLE(XSLT)
220     else if (m_isXSL)
221         downcast<XSLStyleSheet>(*m_sheet).parseString(sheet);
222 #endif
223
224     if (m_cachedSheet)
225         m_cachedSheet->removeClient(*this);
226     m_cachedSheet = nullptr;
227
228     m_loading = false;
229
230     if (m_isCSS)
231         downcast<CSSStyleSheet>(*m_sheet).contents().checkLoaded();
232 #if ENABLE(XSLT)
233     else if (m_isXSL)
234         downcast<XSLStyleSheet>(*m_sheet).checkLoaded();
235 #endif
236 }
237
238 void ProcessingInstruction::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
239 {
240     if (!sheet())
241         return;
242     
243     addSubresourceURL(urls, sheet()->baseURL());
244 }
245
246 Node::InsertionNotificationRequest ProcessingInstruction::insertedInto(ContainerNode& insertionPoint)
247 {
248     CharacterData::insertedInto(insertionPoint);
249     if (!insertionPoint.inDocument())
250         return InsertionDone;
251     document().styleScope().addStyleSheetCandidateNode(*this, m_createdByParser);
252     checkStyleSheet();
253     return InsertionDone;
254 }
255
256 void ProcessingInstruction::removedFrom(ContainerNode& insertionPoint)
257 {
258     CharacterData::removedFrom(insertionPoint);
259     if (!insertionPoint.inDocument())
260         return;
261     
262     document().styleScope().removeStyleSheetCandidateNode(*this);
263
264     if (m_sheet) {
265         ASSERT(m_sheet->ownerNode() == this);
266         m_sheet->clearOwnerNode();
267         m_sheet = nullptr;
268     }
269
270     if (m_loading) {
271         m_loading = false;
272         document().styleScope().removePendingSheet();
273     }
274
275     // If we're in document teardown, then we don't need to do any notification of our sheet's removal.
276     if (document().hasLivingRenderTree())
277         document().styleScope().didChangeContentsOrInterpretation();
278 }
279
280 void ProcessingInstruction::finishParsingChildren()
281 {
282     m_createdByParser = false;
283     CharacterData::finishParsingChildren();
284 }
285
286 } // namespace