8e6b8354cf8ce211e0762751762ea04a5d7288f7
[WebKit-https.git] / Source / WebCore / xml / parser / XMLDocumentParser.cpp
1 /*
2  * Copyright (C) 2000 Peter Kelly (pmk@post.com)
3  * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
4  * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
5  * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
6  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
7  * Copyright (C) 2008 Holger Hans Peter Freyther
8  * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 #include "config.h"
27 #include "XMLDocumentParser.h"
28
29 #include "CDATASection.h"
30 #include "Comment.h"
31 #include "Document.h"
32 #include "DocumentFragment.h"
33 #include "DocumentType.h"
34 #include "Frame.h"
35 #include "FrameLoader.h"
36 #include "FrameView.h"
37 #include "HTMLLinkElement.h"
38 #include "HTMLNames.h"
39 #include "HTMLStyleElement.h"
40 #include "ImageLoader.h"
41 #include "PendingScript.h"
42 #include "ProcessingInstruction.h"
43 #include "ResourceError.h"
44 #include "ResourceRequest.h"
45 #include "ResourceResponse.h"
46 #include "SVGNames.h"
47 #include "SVGStyleElement.h"
48 #include "ScriptElement.h"
49 #include "ScriptSourceCode.h"
50 #include "StyleScope.h"
51 #include "TextResourceDecoder.h"
52 #include "TreeDepthLimit.h"
53 #include <wtf/Ref.h>
54 #include <wtf/StringExtras.h>
55 #include <wtf/Threading.h>
56 #include <wtf/Vector.h>
57
58 namespace WebCore {
59
60 using namespace HTMLNames;
61
62 void XMLDocumentParser::pushCurrentNode(ContainerNode* n)
63 {
64     ASSERT(n);
65     ASSERT(m_currentNode);
66     if (n != document())
67         n->ref();
68     m_currentNodeStack.append(m_currentNode);
69     m_currentNode = n;
70     if (m_currentNodeStack.size() > maxDOMTreeDepth)
71         handleError(XMLErrors::fatal, "Excessive node nesting.", textPosition());
72 }
73
74 void XMLDocumentParser::popCurrentNode()
75 {
76     if (!m_currentNode)
77         return;
78     ASSERT(m_currentNodeStack.size());
79
80     if (m_currentNode != document())
81         m_currentNode->deref();
82
83     m_currentNode = m_currentNodeStack.last();
84     m_currentNodeStack.removeLast();
85 }
86
87 void XMLDocumentParser::clearCurrentNodeStack()
88 {
89     if (m_currentNode && m_currentNode != document())
90         m_currentNode->deref();
91     m_currentNode = nullptr;
92     m_leafTextNode = nullptr;
93
94     if (m_currentNodeStack.size()) { // Aborted parsing.
95         for (size_t i = m_currentNodeStack.size() - 1; i != 0; --i)
96             m_currentNodeStack[i]->deref();
97         if (m_currentNodeStack[0] && m_currentNodeStack[0] != document())
98             m_currentNodeStack[0]->deref();
99         m_currentNodeStack.clear();
100     }
101 }
102
103 void XMLDocumentParser::insert(SegmentedString&&)
104 {
105     ASSERT_NOT_REACHED();
106 }
107
108 void XMLDocumentParser::append(RefPtr<StringImpl>&& inputSource)
109 {
110     String source { WTFMove(inputSource) };
111
112     if (m_sawXSLTransform || !m_sawFirstElement)
113         m_originalSourceForTransform.append(source);
114
115     if (isStopped() || m_sawXSLTransform)
116         return;
117
118     if (m_parserPaused) {
119         m_pendingSrc.append(source);
120         return;
121     }
122
123     doWrite(source);
124
125     // After parsing, dispatch image beforeload events.
126     ImageLoader::dispatchPendingBeforeLoadEvents();
127 }
128
129 void XMLDocumentParser::handleError(XMLErrors::ErrorType type, const char* m, TextPosition position)
130 {
131     if (!m_xmlErrors)
132         m_xmlErrors = std::make_unique<XMLErrors>(*document());
133     m_xmlErrors->handleError(type, m, position);
134     if (type != XMLErrors::warning)
135         m_sawError = true;
136     if (type == XMLErrors::fatal)
137         stopParsing();
138 }
139
140 void XMLDocumentParser::createLeafTextNode()
141 {
142     if (m_leafTextNode)
143         return;
144
145     ASSERT(m_bufferedText.size() == 0);
146     ASSERT(!m_leafTextNode);
147     m_leafTextNode = Text::create(m_currentNode->document(), "");
148     m_currentNode->parserAppendChild(*m_leafTextNode);
149 }
150
151 bool XMLDocumentParser::updateLeafTextNode()
152 {
153     if (isStopped())
154         return false;
155
156     if (!m_leafTextNode)
157         return true;
158
159     // This operation might fire mutation event, see below.
160     m_leafTextNode->appendData(String::fromUTF8(reinterpret_cast<const char*>(m_bufferedText.data()), m_bufferedText.size()));
161     m_bufferedText = { };
162
163     m_leafTextNode = nullptr;
164
165     // Hence, we need to check again whether the parser is stopped, since mutation
166     // event handlers executed by appendData might have detached this parser.
167     return !isStopped();
168 }
169
170 void XMLDocumentParser::detach()
171 {
172     clearCurrentNodeStack();
173     ScriptableDocumentParser::detach();
174 }
175
176 void XMLDocumentParser::end()
177 {
178     // XMLDocumentParserLibxml2 will do bad things to the document if doEnd() is called.
179     // I don't believe XMLDocumentParserQt needs doEnd called in the fragment case.
180     ASSERT(!m_parsingFragment);
181
182     doEnd();
183
184     // doEnd() call above can detach the parser and null out its document.
185     // In that case, we just bail out.
186     if (isDetached())
187         return;
188
189     // doEnd() could process a script tag, thus pausing parsing.
190     if (m_parserPaused)
191         return;
192
193     if (m_sawError) {
194         insertErrorMessageBlock();
195         if (isDetached()) // Inserting an error message may have ran arbitrary scripts.
196             return;
197     } else {
198         updateLeafTextNode();
199         document()->styleScope().didChangeStyleSheetEnvironment();
200     }
201
202     if (isParsing())
203         prepareToStopParsing();
204     document()->setReadyState(Document::Interactive);
205     clearCurrentNodeStack();
206     document()->finishedParsing();
207 }
208
209 void XMLDocumentParser::finish()
210 {
211     // FIXME: We should ASSERT(!m_parserStopped) here, since it does not
212     // makes sense to call any methods on DocumentParser once it's been stopped.
213     // However, FrameLoader::stop calls DocumentParser::finish unconditionally.
214
215     Ref<XMLDocumentParser> protectedThis(*this);
216
217     if (m_parserPaused)
218         m_finishCalled = true;
219     else
220         end();
221 }
222
223 void XMLDocumentParser::insertErrorMessageBlock()
224 {
225     ASSERT(m_xmlErrors);
226     m_xmlErrors->insertErrorMessageBlock();
227 }
228
229 void XMLDocumentParser::notifyFinished(PendingScript& pendingScript)
230 {
231     ASSERT(&pendingScript == m_pendingScript.get());
232
233     // JavaScript can detach this parser, make sure it's kept alive even if detached.
234     Ref<XMLDocumentParser> protectedThis(*this);
235
236     m_pendingScript = nullptr;
237     pendingScript.clearClient();
238
239     pendingScript.element().executePendingScript(pendingScript);
240
241     if (!isDetached() && !m_requestingScript)
242         resumeParsing();
243 }
244
245 bool XMLDocumentParser::isWaitingForScripts() const
246 {
247     return m_pendingScript;
248 }
249
250 void XMLDocumentParser::pauseParsing()
251 {
252     ASSERT(!m_parserPaused);
253
254     if (m_parsingFragment)
255         return;
256
257     m_parserPaused = true;
258 }
259
260 bool XMLDocumentParser::parseDocumentFragment(const String& chunk, DocumentFragment& fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
261 {
262     if (!chunk.length())
263         return true;
264
265     // FIXME: We need to implement the HTML5 XML Fragment parsing algorithm:
266     // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-xhtml-syntax.html#xml-fragment-parsing-algorithm
267     // For now we have a hack for script/style innerHTML support:
268     if (contextElement && (contextElement->hasLocalName(HTMLNames::scriptTag->localName()) || contextElement->hasLocalName(HTMLNames::styleTag->localName()))) {
269         fragment.parserAppendChild(fragment.document().createTextNode(chunk));
270         return true;
271     }
272
273     RefPtr<XMLDocumentParser> parser = XMLDocumentParser::create(fragment, contextElement, parserContentPolicy);
274     bool wellFormed = parser->appendFragmentSource(chunk);
275     // Do not call finish(). The finish() and doEnd() implementations touch the main document and loader and can cause crashes in the fragment case.
276     parser->detach(); // Allows ~DocumentParser to assert it was detached before destruction.
277     return wellFormed; // appendFragmentSource()'s wellFormed is more permissive than Document::wellFormed().
278 }
279
280 } // namespace WebCore