af9fc20f67b4202227ad7e785c149241c4c80a8e
[WebKit-https.git] / Source / WebCore / xml / parser / XMLDocumentParserLibxml2.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, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9  * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
10  * Copyright (C) 2013 Samsung Electronics. All rights reserved.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "XMLDocumentParser.h"
30
31 #include "CDATASection.h"
32 #include "Comment.h"
33 #include "CachedResourceLoader.h"
34 #include "Document.h"
35 #include "DocumentFragment.h"
36 #include "DocumentType.h"
37 #include "Frame.h"
38 #include "HTMLEntityParser.h"
39 #include "HTMLHtmlElement.h"
40 #include "HTMLTemplateElement.h"
41 #include "InlineClassicScript.h"
42 #include "PendingScript.h"
43 #include "ProcessingInstruction.h"
44 #include "ResourceError.h"
45 #include "ResourceResponse.h"
46 #include "ScriptElement.h"
47 #include "ScriptSourceCode.h"
48 #include "Settings.h"
49 #include "StyleScope.h"
50 #include "TransformSource.h"
51 #include "XMLNSNames.h"
52 #include "XMLDocumentParserScope.h"
53 #include <libxml/parserInternals.h>
54 #include <wtf/StringExtras.h>
55 #include <wtf/unicode/UTF8.h>
56
57 #if ENABLE(XSLT)
58 #include "XMLTreeViewer.h"
59 #include <libxslt/xslt.h>
60 #endif
61
62 namespace WebCore {
63
64 #if ENABLE(XSLT)
65
66 static inline bool shouldRenderInXMLTreeViewerMode(Document& document)
67 {
68     if (document.sawElementsInKnownNamespaces())
69         return false;
70
71     if (document.transformSourceDocument())
72         return false;
73
74     auto* frame = document.frame();
75     if (!frame)
76         return false;
77
78     if (!frame->settings().developerExtrasEnabled())
79         return false;
80
81     if (frame->tree().parent())
82         return false; // This document is not in a top frame
83
84     return true;
85 }
86
87 #endif
88
89 class PendingCallbacks {
90     WTF_MAKE_FAST_ALLOCATED;
91 public:
92     void appendStartElementNSCallback(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int numNamespaces, const xmlChar** namespaces, int numAttributes, int numDefaulted, const xmlChar** attributes)
93     {
94         auto callback = std::make_unique<PendingStartElementNSCallback>();
95
96         callback->xmlLocalName = xmlStrdup(xmlLocalName);
97         callback->xmlPrefix = xmlStrdup(xmlPrefix);
98         callback->xmlURI = xmlStrdup(xmlURI);
99         callback->numNamespaces = numNamespaces;
100         callback->namespaces = static_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * numNamespaces * 2));
101         for (int i = 0; i < numNamespaces * 2 ; i++)
102             callback->namespaces[i] = xmlStrdup(namespaces[i]);
103         callback->numAttributes = numAttributes;
104         callback->numDefaulted = numDefaulted;
105         callback->attributes = static_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * numAttributes * 5));
106         for (int i = 0; i < numAttributes; i++) {
107             // Each attribute has 5 elements in the array:
108             // name, prefix, uri, value and an end pointer.
109
110             for (int j = 0; j < 3; j++)
111                 callback->attributes[i * 5 + j] = xmlStrdup(attributes[i * 5 + j]);
112
113             int len = attributes[i * 5 + 4] - attributes[i * 5 + 3];
114
115             callback->attributes[i * 5 + 3] = xmlStrndup(attributes[i * 5 + 3], len);
116             callback->attributes[i * 5 + 4] = callback->attributes[i * 5 + 3] + len;
117         }
118
119         m_callbacks.append(WTFMove(callback));
120     }
121
122     void appendEndElementNSCallback()
123     {
124         m_callbacks.append(std::make_unique<PendingEndElementNSCallback>());
125     }
126
127     void appendCharactersCallback(const xmlChar* s, int len)
128     {
129         auto callback = std::make_unique<PendingCharactersCallback>();
130
131         callback->s = xmlStrndup(s, len);
132         callback->len = len;
133
134         m_callbacks.append(WTFMove(callback));
135     }
136
137     void appendProcessingInstructionCallback(const xmlChar* target, const xmlChar* data)
138     {
139         auto callback = std::make_unique<PendingProcessingInstructionCallback>();
140
141         callback->target = xmlStrdup(target);
142         callback->data = xmlStrdup(data);
143
144         m_callbacks.append(WTFMove(callback));
145     }
146
147     void appendCDATABlockCallback(const xmlChar* s, int len)
148     {
149         auto callback = std::make_unique<PendingCDATABlockCallback>();
150
151         callback->s = xmlStrndup(s, len);
152         callback->len = len;
153
154         m_callbacks.append(WTFMove(callback));
155     }
156
157     void appendCommentCallback(const xmlChar* s)
158     {
159         auto callback = std::make_unique<PendingCommentCallback>();
160
161         callback->s = xmlStrdup(s);
162
163         m_callbacks.append(WTFMove(callback));
164     }
165
166     void appendInternalSubsetCallback(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID)
167     {
168         auto callback = std::make_unique<PendingInternalSubsetCallback>();
169
170         callback->name = xmlStrdup(name);
171         callback->externalID = xmlStrdup(externalID);
172         callback->systemID = xmlStrdup(systemID);
173
174         m_callbacks.append(WTFMove(callback));
175     }
176
177     void appendErrorCallback(XMLErrors::ErrorType type, const xmlChar* message, OrdinalNumber lineNumber, OrdinalNumber columnNumber)
178     {
179         auto callback = std::make_unique<PendingErrorCallback>();
180
181         callback->message = xmlStrdup(message);
182         callback->type = type;
183         callback->lineNumber = lineNumber;
184         callback->columnNumber = columnNumber;
185
186         m_callbacks.append(WTFMove(callback));
187     }
188
189     void callAndRemoveFirstCallback(XMLDocumentParser* parser)
190     {
191         std::unique_ptr<PendingCallback> callback = m_callbacks.takeFirst();
192         callback->call(parser);
193     }
194
195     bool isEmpty() const { return m_callbacks.isEmpty(); }
196
197 private:
198     struct PendingCallback {
199         virtual ~PendingCallback() { }
200         virtual void call(XMLDocumentParser* parser) = 0;
201     };
202
203     struct PendingStartElementNSCallback : public PendingCallback {
204         virtual ~PendingStartElementNSCallback()
205         {
206             xmlFree(xmlLocalName);
207             xmlFree(xmlPrefix);
208             xmlFree(xmlURI);
209             for (int i = 0; i < numNamespaces * 2; i++)
210                 xmlFree(namespaces[i]);
211             xmlFree(namespaces);
212             for (int i = 0; i < numAttributes; i++) {
213                 for (int j = 0; j < 4; j++)
214                     xmlFree(attributes[i * 5 + j]);
215             }
216             xmlFree(attributes);
217         }
218
219         void call(XMLDocumentParser* parser) override
220         {
221             parser->startElementNs(xmlLocalName, xmlPrefix, xmlURI, numNamespaces, const_cast<const xmlChar**>(namespaces), numAttributes, numDefaulted, const_cast<const xmlChar**>(attributes));
222         }
223
224         xmlChar* xmlLocalName;
225         xmlChar* xmlPrefix;
226         xmlChar* xmlURI;
227         int numNamespaces;
228         xmlChar** namespaces;
229         int numAttributes;
230         int numDefaulted;
231         xmlChar** attributes;
232     };
233
234     struct PendingEndElementNSCallback : public PendingCallback {
235         void call(XMLDocumentParser* parser) override
236         {
237             parser->endElementNs();
238         }
239     };
240
241     struct PendingCharactersCallback : public PendingCallback {
242         virtual ~PendingCharactersCallback()
243         {
244             xmlFree(s);
245         }
246
247         void call(XMLDocumentParser* parser) override
248         {
249             parser->characters(s, len);
250         }
251
252         xmlChar* s;
253         int len;
254     };
255
256     struct PendingProcessingInstructionCallback : public PendingCallback {
257         virtual ~PendingProcessingInstructionCallback()
258         {
259             xmlFree(target);
260             xmlFree(data);
261         }
262
263         void call(XMLDocumentParser* parser) override
264         {
265             parser->processingInstruction(target, data);
266         }
267
268         xmlChar* target;
269         xmlChar* data;
270     };
271
272     struct PendingCDATABlockCallback : public PendingCallback {
273         virtual ~PendingCDATABlockCallback()
274         {
275             xmlFree(s);
276         }
277
278         void call(XMLDocumentParser* parser) override
279         {
280             parser->cdataBlock(s, len);
281         }
282
283         xmlChar* s;
284         int len;
285     };
286
287     struct PendingCommentCallback : public PendingCallback {
288         virtual ~PendingCommentCallback()
289         {
290             xmlFree(s);
291         }
292
293         void call(XMLDocumentParser* parser) override
294         {
295             parser->comment(s);
296         }
297
298         xmlChar* s;
299     };
300
301     struct PendingInternalSubsetCallback : public PendingCallback {
302         virtual ~PendingInternalSubsetCallback()
303         {
304             xmlFree(name);
305             xmlFree(externalID);
306             xmlFree(systemID);
307         }
308
309         void call(XMLDocumentParser* parser) override
310         {
311             parser->internalSubset(name, externalID, systemID);
312         }
313
314         xmlChar* name;
315         xmlChar* externalID;
316         xmlChar* systemID;
317     };
318
319     struct PendingErrorCallback: public PendingCallback {
320         virtual ~PendingErrorCallback()
321         {
322             xmlFree(message);
323         }
324
325         void call(XMLDocumentParser* parser) override
326         {
327             parser->handleError(type, reinterpret_cast<char*>(message), TextPosition(lineNumber, columnNumber));
328         }
329
330         XMLErrors::ErrorType type;
331         xmlChar* message;
332         OrdinalNumber lineNumber;
333         OrdinalNumber columnNumber;
334     };
335
336     Deque<std::unique_ptr<PendingCallback>> m_callbacks;
337 };
338 // --------------------------------
339
340 static int globalDescriptor = 0;
341 static ThreadIdentifier libxmlLoaderThread = 0;
342
343 static int matchFunc(const char*)
344 {
345     // Only match loads initiated due to uses of libxml2 from within XMLDocumentParser to avoid
346     // interfering with client applications that also use libxml2.  http://bugs.webkit.org/show_bug.cgi?id=17353
347     return XMLDocumentParserScope::currentCachedResourceLoader && currentThread() == libxmlLoaderThread;
348 }
349
350 class OffsetBuffer {
351     WTF_MAKE_FAST_ALLOCATED;
352 public:
353     OffsetBuffer(Vector<char> buffer)
354         : m_buffer(WTFMove(buffer))
355         , m_currentOffset(0)
356     {
357     }
358
359     int readOutBytes(char* outputBuffer, unsigned askedToRead)
360     {
361         unsigned bytesLeft = m_buffer.size() - m_currentOffset;
362         unsigned lenToCopy = std::min(askedToRead, bytesLeft);
363         if (lenToCopy) {
364             memcpy(outputBuffer, m_buffer.data() + m_currentOffset, lenToCopy);
365             m_currentOffset += lenToCopy;
366         }
367         return lenToCopy;
368     }
369
370 private:
371     Vector<char> m_buffer;
372     unsigned m_currentOffset;
373 };
374
375 static inline void setAttributes(Element* element, Vector<Attribute>& attributeVector, ParserContentPolicy parserContentPolicy)
376 {
377     if (!scriptingContentIsAllowed(parserContentPolicy))
378         element->stripScriptingAttributes(attributeVector);
379     element->parserSetAttributes(attributeVector);
380 }
381
382 static void switchToUTF16(xmlParserCtxtPtr ctxt)
383 {
384     // Hack around libxml2's lack of encoding overide support by manually
385     // resetting the encoding to UTF-16 before every chunk.  Otherwise libxml
386     // will detect <?xml version="1.0" encoding="<encoding name>"?> blocks
387     // and switch encodings, causing the parse to fail.
388
389     // FIXME: Can we just use XML_PARSE_IGNORE_ENC now?
390
391     const UChar BOM = 0xFEFF;
392     const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
393     xmlSwitchEncoding(ctxt, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE);
394 }
395
396 static bool shouldAllowExternalLoad(const URL& url)
397 {
398     String urlString = url.string();
399
400     // On non-Windows platforms libxml asks for this URL, the
401     // "XML_XML_DEFAULT_CATALOG", on initialization.
402     if (urlString == "file:///etc/xml/catalog")
403         return false;
404
405     // On Windows, libxml computes a URL relative to where its DLL resides.
406     if (urlString.startsWith("file:///", false) && urlString.endsWith("/etc/catalog", false))
407         return false;
408
409     // The most common DTD.  There isn't much point in hammering www.w3c.org
410     // by requesting this URL for every XHTML document.
411     if (urlString.startsWith("http://www.w3.org/TR/xhtml", false))
412         return false;
413
414     // Similarly, there isn't much point in requesting the SVG DTD.
415     if (urlString.startsWith("http://www.w3.org/Graphics/SVG", false))
416         return false;
417
418     // The libxml doesn't give us a lot of context for deciding whether to
419     // allow this request.  In the worst case, this load could be for an
420     // external entity and the resulting document could simply read the
421     // retrieved content.  If we had more context, we could potentially allow
422     // the parser to load a DTD.  As things stand, we take the conservative
423     // route and allow same-origin requests only.
424     if (!XMLDocumentParserScope::currentCachedResourceLoader->document()->securityOrigin()->canRequest(url)) {
425         XMLDocumentParserScope::currentCachedResourceLoader->printAccessDeniedMessage(url);
426         return false;
427     }
428
429     return true;
430 }
431
432 static void* openFunc(const char* uri)
433 {
434     ASSERT(XMLDocumentParserScope::currentCachedResourceLoader);
435     ASSERT(currentThread() == libxmlLoaderThread);
436
437     URL url(URL(), uri);
438
439     if (!shouldAllowExternalLoad(url))
440         return &globalDescriptor;
441
442     ResourceError error;
443     ResourceResponse response;
444     RefPtr<SharedBuffer> data;
445
446
447     {
448         CachedResourceLoader* cachedResourceLoader = XMLDocumentParserScope::currentCachedResourceLoader;
449         XMLDocumentParserScope scope(nullptr);
450         // FIXME: We should restore the original global error handler as well.
451
452         if (cachedResourceLoader->frame())
453             cachedResourceLoader->frame()->loader().loadResourceSynchronously(url, AllowStoredCredentials, ClientCredentialPolicy::MayAskClientForCredentials, error, response, data);
454     }
455
456     // We have to check the URL again after the load to catch redirects.
457     // See <https://bugs.webkit.org/show_bug.cgi?id=21963>.
458     if (!shouldAllowExternalLoad(response.url()))
459         return &globalDescriptor;
460     Vector<char> buffer;
461     if (data)
462         buffer.append(data->data(), data->size());
463     return new OffsetBuffer(WTFMove(buffer));
464 }
465
466 static int readFunc(void* context, char* buffer, int len)
467 {
468     // Do 0-byte reads in case of a null descriptor
469     if (context == &globalDescriptor)
470         return 0;
471
472     OffsetBuffer* data = static_cast<OffsetBuffer*>(context);
473     return data->readOutBytes(buffer, len);
474 }
475
476 static int writeFunc(void*, const char*, int)
477 {
478     // Always just do 0-byte writes
479     return 0;
480 }
481
482 static int closeFunc(void* context)
483 {
484     if (context != &globalDescriptor) {
485         OffsetBuffer* data = static_cast<OffsetBuffer*>(context);
486         delete data;
487     }
488     return 0;
489 }
490
491 #if ENABLE(XSLT)
492 static void errorFunc(void*, const char*, ...)
493 {
494     // FIXME: It would be nice to display error messages somewhere.
495 }
496 #endif
497
498 static bool didInit = false;
499
500 Ref<XMLParserContext> XMLParserContext::createStringParser(xmlSAXHandlerPtr handlers, void* userData)
501 {
502     if (!didInit) {
503         xmlInitParser();
504         xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, closeFunc);
505         xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, closeFunc);
506         libxmlLoaderThread = currentThread();
507         didInit = true;
508     }
509
510     xmlParserCtxtPtr parser = xmlCreatePushParserCtxt(handlers, 0, 0, 0, 0);
511     parser->_private = userData;
512
513     // Substitute entities.
514     xmlCtxtUseOptions(parser, XML_PARSE_NOENT);
515
516     switchToUTF16(parser);
517
518     return adoptRef(*new XMLParserContext(parser));
519 }
520
521
522 // Chunk should be encoded in UTF-8
523 RefPtr<XMLParserContext> XMLParserContext::createMemoryParser(xmlSAXHandlerPtr handlers, void* userData, const CString& chunk)
524 {
525     if (!didInit) {
526         xmlInitParser();
527         xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, closeFunc);
528         xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, closeFunc);
529         libxmlLoaderThread = currentThread();
530         didInit = true;
531     }
532
533     // appendFragmentSource() checks that the length doesn't overflow an int.
534     xmlParserCtxtPtr parser = xmlCreateMemoryParserCtxt(chunk.data(), chunk.length());
535
536     if (!parser)
537         return 0;
538
539     memcpy(parser->sax, handlers, sizeof(xmlSAXHandler));
540
541     // Substitute entities.
542     // FIXME: Why is XML_PARSE_NODICT needed? This is different from what createStringParser does.
543     xmlCtxtUseOptions(parser, XML_PARSE_NODICT | XML_PARSE_NOENT);
544
545     // Internal initialization
546     parser->sax2 = 1;
547     parser->instate = XML_PARSER_CONTENT; // We are parsing a CONTENT
548     parser->depth = 0;
549     parser->str_xml = xmlDictLookup(parser->dict, BAD_CAST "xml", 3);
550     parser->str_xmlns = xmlDictLookup(parser->dict, BAD_CAST "xmlns", 5);
551     parser->str_xml_ns = xmlDictLookup(parser->dict, XML_XML_NAMESPACE, 36);
552     parser->_private = userData;
553
554     return adoptRef(*new XMLParserContext(parser));
555 }
556
557 // --------------------------------
558
559 bool XMLDocumentParser::supportsXMLVersion(const String& version)
560 {
561     return version == "1.0";
562 }
563
564 XMLDocumentParser::XMLDocumentParser(Document& document, FrameView* frameView)
565     : ScriptableDocumentParser(document)
566     , m_view(frameView)
567     , m_pendingCallbacks(std::make_unique<PendingCallbacks>())
568     , m_currentNode(&document)
569     , m_scriptStartPosition(TextPosition::belowRangePosition())
570 {
571 }
572
573 XMLDocumentParser::XMLDocumentParser(DocumentFragment& fragment, Element* parentElement, ParserContentPolicy parserContentPolicy)
574     : ScriptableDocumentParser(fragment.document(), parserContentPolicy)
575     , m_pendingCallbacks(std::make_unique<PendingCallbacks>())
576     , m_currentNode(&fragment)
577     , m_scriptStartPosition(TextPosition::belowRangePosition())
578     , m_parsingFragment(true)
579 {
580     fragment.ref();
581
582     // Add namespaces based on the parent node
583     Vector<Element*> elemStack;
584     while (parentElement) {
585         elemStack.append(parentElement);
586
587         ContainerNode* node = parentElement->parentNode();
588         if (!is<Element>(node))
589             break;
590         parentElement = downcast<Element>(node);
591     }
592
593     if (elemStack.isEmpty())
594         return;
595
596     // FIXME: Share code with isDefaultNamespace() per http://www.whatwg.org/specs/web-apps/current-work/multipage/the-xhtml-syntax.html#parsing-xhtml-fragments
597     for (; !elemStack.isEmpty(); elemStack.removeLast()) {
598         Element* element = elemStack.last();
599         if (element->hasAttributes()) {
600             for (const Attribute& attribute : element->attributesIterator()) {
601                 if (attribute.localName() == xmlnsAtom)
602                     m_defaultNamespaceURI = attribute.value();
603                 else if (attribute.prefix() == xmlnsAtom)
604                     m_prefixToNamespaceMap.set(attribute.localName(), attribute.value());
605             }
606         }
607     }
608
609     if (m_defaultNamespaceURI.isNull())
610         m_defaultNamespaceURI = parentElement->namespaceURI();
611 }
612
613 XMLParserContext::~XMLParserContext()
614 {
615     if (m_context->myDoc)
616         xmlFreeDoc(m_context->myDoc);
617     xmlFreeParserCtxt(m_context);
618 }
619
620 XMLDocumentParser::~XMLDocumentParser()
621 {
622     // The XMLDocumentParser will always be detached before being destroyed.
623     ASSERT(m_currentNodeStack.isEmpty());
624     ASSERT(!m_currentNode);
625
626     // FIXME: m_pendingScript handling should be moved into XMLDocumentParser.cpp!
627     if (m_pendingScript)
628         m_pendingScript->clearClient();
629 }
630
631 void XMLDocumentParser::doWrite(const String& parseString)
632 {
633     ASSERT(!isDetached());
634     if (!m_context)
635         initializeParserContext();
636
637     // Protect the libxml context from deletion during a callback
638     RefPtr<XMLParserContext> context = m_context;
639
640     // libXML throws an error if you try to switch the encoding for an empty string.
641     if (parseString.length()) {
642         // JavaScript may cause the parser to detach during xmlParseChunk
643         // keep this alive until this function is done.
644         Ref<XMLDocumentParser> protectedThis(*this);
645
646         XMLDocumentParserScope scope(&document()->cachedResourceLoader());
647
648         // FIXME: Can we parse 8-bit strings directly as Latin-1 instead of upconverting to UTF-16?
649         switchToUTF16(context->context());
650         xmlParseChunk(context->context(), reinterpret_cast<const char*>(StringView(parseString).upconvertedCharacters().get()), sizeof(UChar) * parseString.length(), 0);
651
652         // JavaScript (which may be run under the xmlParseChunk callstack) may
653         // cause the parser to be stopped or detached.
654         if (isStopped())
655             return;
656     }
657
658     // FIXME: Why is this here?  And why is it after we process the passed source?
659     if (document()->decoder() && document()->decoder()->sawError()) {
660         // If the decoder saw an error, report it as fatal (stops parsing)
661         TextPosition position(OrdinalNumber::fromOneBasedInt(context->context()->input->line), OrdinalNumber::fromOneBasedInt(context->context()->input->col));
662         handleError(XMLErrors::fatal, "Encoding error", position);
663     }
664 }
665
666 static inline String toString(const xmlChar* string, size_t size)
667 {
668     return String::fromUTF8(reinterpret_cast<const char*>(string), size);
669 }
670
671 static inline String toString(const xmlChar* string)
672 {
673     return String::fromUTF8(reinterpret_cast<const char*>(string));
674 }
675
676 static inline AtomicString toAtomicString(const xmlChar* string, size_t size)
677 {
678     return AtomicString::fromUTF8(reinterpret_cast<const char*>(string), size);
679 }
680
681 static inline AtomicString toAtomicString(const xmlChar* string)
682 {
683     return AtomicString::fromUTF8(reinterpret_cast<const char*>(string));
684 }
685
686 struct _xmlSAX2Namespace {
687     const xmlChar* prefix;
688     const xmlChar* uri;
689 };
690 typedef struct _xmlSAX2Namespace xmlSAX2Namespace;
691
692 static inline bool handleNamespaceAttributes(Vector<Attribute>& prefixedAttributes, const xmlChar** libxmlNamespaces, int numNamespaces)
693 {
694     xmlSAX2Namespace* namespaces = reinterpret_cast<xmlSAX2Namespace*>(libxmlNamespaces);
695     for (int i = 0; i < numNamespaces; i++) {
696         AtomicString namespaceQName = xmlnsAtom;
697         AtomicString namespaceURI = toAtomicString(namespaces[i].uri);
698         if (namespaces[i].prefix)
699             namespaceQName = "xmlns:" + toString(namespaces[i].prefix);
700
701         auto result = Element::parseAttributeName(XMLNSNames::xmlnsNamespaceURI, namespaceQName);
702         if (result.hasException())
703             return false;
704
705         prefixedAttributes.append(Attribute(result.releaseReturnValue(), namespaceURI));
706     }
707     return true;
708 }
709
710 struct _xmlSAX2Attributes {
711     const xmlChar* localname;
712     const xmlChar* prefix;
713     const xmlChar* uri;
714     const xmlChar* value;
715     const xmlChar* end;
716 };
717 typedef struct _xmlSAX2Attributes xmlSAX2Attributes;
718
719 static inline bool handleElementAttributes(Vector<Attribute>& prefixedAttributes, const xmlChar** libxmlAttributes, int numAttributes)
720 {
721     xmlSAX2Attributes* attributes = reinterpret_cast<xmlSAX2Attributes*>(libxmlAttributes);
722     for (int i = 0; i < numAttributes; i++) {
723         int valueLength = static_cast<int>(attributes[i].end - attributes[i].value);
724         AtomicString attrValue = toAtomicString(attributes[i].value, valueLength);
725         String attrPrefix = toString(attributes[i].prefix);
726         AtomicString attrURI = attrPrefix.isEmpty() ? nullAtom : toAtomicString(attributes[i].uri);
727         AtomicString attrQName = attrPrefix.isEmpty() ? toAtomicString(attributes[i].localname) : attrPrefix + ":" + toString(attributes[i].localname);
728
729         auto result = Element::parseAttributeName(attrURI, attrQName);
730         if (result.hasException())
731             return false;
732
733         prefixedAttributes.append(Attribute(result.releaseReturnValue(), attrValue));
734     }
735     return true;
736 }
737
738 // This is a hack around https://bugzilla.gnome.org/show_bug.cgi?id=502960
739 // Otherwise libxml doesn't include namespace for parsed entities, breaking entity
740 // expansion for all entities containing elements.
741 static inline bool hackAroundLibXMLEntityParsingBug()
742 {
743 #if LIBXML_VERSION >= 20704
744     // This bug has been fixed in libxml 2.7.4.
745     return false;
746 #else
747     return true;
748 #endif
749 }
750
751 void XMLDocumentParser::startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int numNamespaces, const xmlChar** libxmlNamespaces, int numAttributes, int numDefaulted, const xmlChar** libxmlAttributes)
752 {
753     if (isStopped())
754         return;
755
756     if (m_parserPaused) {
757         m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, numNamespaces, libxmlNamespaces, numAttributes, numDefaulted, libxmlAttributes);
758         return;
759     }
760
761     if (!updateLeafTextNode())
762         return;
763
764     AtomicString localName = toAtomicString(xmlLocalName);
765     AtomicString uri = toAtomicString(xmlURI);
766     AtomicString prefix = toAtomicString(xmlPrefix);
767
768     if (m_parsingFragment && uri.isNull()) {
769         if (!prefix.isNull())
770             uri = m_prefixToNamespaceMap.get(prefix);
771         else
772             uri = m_defaultNamespaceURI;
773     }
774
775     // If libxml entity parsing is broken, transfer the currentNodes' namespaceURI to the new node,
776     // if we're currently expanding elements which originate from an entity declaration.
777     if (hackAroundLibXMLEntityParsingBug() && depthTriggeringEntityExpansion() != -1 && context()->depth > depthTriggeringEntityExpansion() && uri.isNull() && prefix.isNull())
778         uri = m_currentNode->namespaceURI();
779
780     bool isFirstElement = !m_sawFirstElement;
781     m_sawFirstElement = true;
782
783     QualifiedName qName(prefix, localName, uri);
784     auto newElement = m_currentNode->document().createElement(qName, true);
785
786     Vector<Attribute> prefixedAttributes;
787     if (!handleNamespaceAttributes(prefixedAttributes, libxmlNamespaces, numNamespaces)) {
788         setAttributes(newElement.ptr(), prefixedAttributes, parserContentPolicy());
789         stopParsing();
790         return;
791     }
792
793     bool success = handleElementAttributes(prefixedAttributes, libxmlAttributes, numAttributes);
794     setAttributes(newElement.ptr(), prefixedAttributes, parserContentPolicy());
795     if (!success) {
796         stopParsing();
797         return;
798     }
799
800     newElement->beginParsingChildren();
801
802     if (isScriptElement(newElement.get()))
803         m_scriptStartPosition = textPosition();
804
805     m_currentNode->parserAppendChild(newElement);
806     if (!m_currentNode) // Synchronous DOM events may have removed the current node.
807         return;
808
809     if (is<HTMLTemplateElement>(newElement))
810         pushCurrentNode(&downcast<HTMLTemplateElement>(newElement.get()).content());
811     else
812         pushCurrentNode(newElement.ptr());
813
814     if (is<HTMLHtmlElement>(newElement))
815         downcast<HTMLHtmlElement>(newElement.get()).insertedByParser();
816
817     if (!m_parsingFragment && isFirstElement && document()->frame())
818         document()->frame()->injectUserScripts(InjectAtDocumentStart);
819 }
820
821 void XMLDocumentParser::endElementNs()
822 {
823     if (isStopped())
824         return;
825
826     if (m_parserPaused) {
827         m_pendingCallbacks->appendEndElementNSCallback();
828         return;
829     }
830
831     // JavaScript can detach the parser.  Make sure this is not released
832     // before the end of this method.
833     Ref<XMLDocumentParser> protectedThis(*this);
834
835     if (!updateLeafTextNode())
836         return;
837
838     RefPtr<ContainerNode> node = m_currentNode;
839     node->finishParsingChildren();
840
841     // Once we reach the depth again where entity expansion started, stop executing the work-around.
842     if (hackAroundLibXMLEntityParsingBug() && context()->depth <= depthTriggeringEntityExpansion())
843         setDepthTriggeringEntityExpansion(-1);
844
845     if (!scriptingContentIsAllowed(parserContentPolicy()) && is<Element>(*node) && isScriptElement(downcast<Element>(*node))) {
846         popCurrentNode();
847         node->remove();
848         return;
849     }
850
851     if (!node->isElementNode() || !m_view) {
852         popCurrentNode();
853         return;
854     }
855
856     auto& element = downcast<Element>(*node);
857
858     // The element's parent may have already been removed from document.
859     // Parsing continues in this case, but scripts aren't executed.
860     if (!element.inDocument()) {
861         popCurrentNode();
862         return;
863     }
864
865     if (!isScriptElement(element)) {
866         popCurrentNode();
867         return;
868     }
869
870     // Don't load external scripts for standalone documents (for now).
871     ASSERT(!m_pendingScript);
872     m_requestingScript = true;
873
874     auto& scriptElement = downcastScriptElement(element);
875     if (scriptElement.prepareScript(m_scriptStartPosition, ScriptElement::AllowLegacyTypeInTypeAttribute)) {
876         // FIXME: Script execution should be shared between
877         // the libxml2 and Qt XMLDocumentParser implementations.
878
879         if (scriptElement.readyToBeParserExecuted())
880             scriptElement.executeClassicScript(ScriptSourceCode(scriptElement.scriptContent(), document()->url(), m_scriptStartPosition, JSC::SourceProviderSourceType::Program, InlineClassicScript::create(scriptElement)));
881         else if (scriptElement.willBeParserExecuted() && scriptElement.loadableScript()) {
882             m_pendingScript = PendingScript::create(scriptElement, *scriptElement.loadableScript());
883             m_pendingScript->setClient(*this);
884
885             // m_pendingScript will be nullptr if script was already loaded and setClient() executed it.
886             if (m_pendingScript)
887                 pauseParsing();
888         }
889
890         // JavaScript may have detached the parser
891         if (isDetached())
892             return;
893     }
894     m_requestingScript = false;
895     popCurrentNode();
896 }
897
898 void XMLDocumentParser::characters(const xmlChar* characters, int length)
899 {
900     if (isStopped())
901         return;
902
903     if (m_parserPaused) {
904         m_pendingCallbacks->appendCharactersCallback(characters, length);
905         return;
906     }
907
908     if (!m_leafTextNode)
909         createLeafTextNode();
910     m_bufferedText.append(characters, length);
911 }
912
913 void XMLDocumentParser::error(XMLErrors::ErrorType type, const char* message, va_list args)
914 {
915     if (isStopped())
916         return;
917
918     va_list preflightArgs;
919     va_copy(preflightArgs, args);
920     size_t stringLength = vsnprintf(nullptr, 0, message, preflightArgs);
921     va_end(preflightArgs);
922
923     Vector<char, 1024> buffer(stringLength + 1);
924     vsnprintf(buffer.data(), stringLength + 1, message, args);
925
926     TextPosition position = textPosition();
927     if (m_parserPaused)
928         m_pendingCallbacks->appendErrorCallback(type, reinterpret_cast<const xmlChar*>(buffer.data()), position.m_line, position.m_column);
929     else
930         handleError(type, buffer.data(), textPosition());
931 }
932
933 void XMLDocumentParser::processingInstruction(const xmlChar* target, const xmlChar* data)
934 {
935     if (isStopped())
936         return;
937
938     if (m_parserPaused) {
939         m_pendingCallbacks->appendProcessingInstructionCallback(target, data);
940         return;
941     }
942
943     if (!updateLeafTextNode())
944         return;
945
946     auto result = m_currentNode->document().createProcessingInstruction(toString(target), toString(data));
947     if (result.hasException())
948         return;
949     auto pi = result.releaseReturnValue();
950
951     pi->setCreatedByParser(true);
952
953     m_currentNode->parserAppendChild(pi);
954
955     pi->finishParsingChildren();
956
957     if (pi->isCSS())
958         m_sawCSS = true;
959
960 #if ENABLE(XSLT)
961     m_sawXSLTransform = !m_sawFirstElement && pi->isXSL();
962     if (m_sawXSLTransform && !document()->transformSourceDocument())
963         stopParsing();
964 #endif
965 }
966
967 void XMLDocumentParser::cdataBlock(const xmlChar* s, int len)
968 {
969     if (isStopped())
970         return;
971
972     if (m_parserPaused) {
973         m_pendingCallbacks->appendCDATABlockCallback(s, len);
974         return;
975     }
976
977     if (!updateLeafTextNode())
978         return;
979
980     m_currentNode->parserAppendChild(CDATASection::create(m_currentNode->document(), toString(s, len)));
981 }
982
983 void XMLDocumentParser::comment(const xmlChar* s)
984 {
985     if (isStopped())
986         return;
987
988     if (m_parserPaused) {
989         m_pendingCallbacks->appendCommentCallback(s);
990         return;
991     }
992
993     if (!updateLeafTextNode())
994         return;
995
996     m_currentNode->parserAppendChild(Comment::create(m_currentNode->document(), toString(s)));
997 }
998
999 enum StandaloneInfo {
1000     StandaloneUnspecified = -2,
1001     NoXMlDeclaration,
1002     StandaloneNo,
1003     StandaloneYes
1004 };
1005
1006 void XMLDocumentParser::startDocument(const xmlChar* version, const xmlChar* encoding, int standalone)
1007 {
1008     StandaloneInfo standaloneInfo = (StandaloneInfo)standalone;
1009     if (standaloneInfo == NoXMlDeclaration) {
1010         document()->setHasXMLDeclaration(false);
1011         return;
1012     }
1013
1014     if (version)
1015         document()->setXMLVersion(toString(version));
1016     if (standalone != StandaloneUnspecified)
1017         document()->setXMLStandalone(standaloneInfo == StandaloneYes);
1018     if (encoding)
1019         document()->setXMLEncoding(toString(encoding));
1020     document()->setHasXMLDeclaration(true);
1021 }
1022
1023 void XMLDocumentParser::endDocument()
1024 {
1025     updateLeafTextNode();
1026 }
1027
1028 void XMLDocumentParser::internalSubset(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID)
1029 {
1030     if (isStopped())
1031         return;
1032
1033     if (m_parserPaused) {
1034         m_pendingCallbacks->appendInternalSubsetCallback(name, externalID, systemID);
1035         return;
1036     }
1037
1038     if (document())
1039         document()->parserAppendChild(DocumentType::create(*document(), toString(name), toString(externalID), toString(systemID)));
1040 }
1041
1042 static inline XMLDocumentParser* getParser(void* closure)
1043 {
1044     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1045     return static_cast<XMLDocumentParser*>(ctxt->_private);
1046 }
1047
1048 // This is a hack around http://bugzilla.gnome.org/show_bug.cgi?id=159219
1049 // Otherwise libxml seems to call all the SAX callbacks twice for any replaced entity.
1050 static inline bool hackAroundLibXMLEntityBug(void* closure)
1051 {
1052 #if LIBXML_VERSION >= 20627
1053     // This bug has been fixed in libxml 2.6.27.
1054     UNUSED_PARAM(closure);
1055     return false;
1056 #else
1057     return static_cast<xmlParserCtxtPtr>(closure)->node;
1058 #endif
1059 }
1060
1061 static void startElementNsHandler(void* closure, const xmlChar* localname, const xmlChar* prefix, const xmlChar* uri, int numNamespaces, const xmlChar** namespaces, int numAttributes, int numDefaulted, const xmlChar** libxmlAttributes)
1062 {
1063     if (hackAroundLibXMLEntityBug(closure))
1064         return;
1065
1066     getParser(closure)->startElementNs(localname, prefix, uri, numNamespaces, namespaces, numAttributes, numDefaulted, libxmlAttributes);
1067 }
1068
1069 static void endElementNsHandler(void* closure, const xmlChar*, const xmlChar*, const xmlChar*)
1070 {
1071     if (hackAroundLibXMLEntityBug(closure))
1072         return;
1073
1074     getParser(closure)->endElementNs();
1075 }
1076
1077 static void charactersHandler(void* closure, const xmlChar* s, int len)
1078 {
1079     if (hackAroundLibXMLEntityBug(closure))
1080         return;
1081
1082     getParser(closure)->characters(s, len);
1083 }
1084
1085 static void processingInstructionHandler(void* closure, const xmlChar* target, const xmlChar* data)
1086 {
1087     if (hackAroundLibXMLEntityBug(closure))
1088         return;
1089
1090     getParser(closure)->processingInstruction(target, data);
1091 }
1092
1093 static void cdataBlockHandler(void* closure, const xmlChar* s, int len)
1094 {
1095     if (hackAroundLibXMLEntityBug(closure))
1096         return;
1097
1098     getParser(closure)->cdataBlock(s, len);
1099 }
1100
1101 static void commentHandler(void* closure, const xmlChar* comment)
1102 {
1103     if (hackAroundLibXMLEntityBug(closure))
1104         return;
1105
1106     getParser(closure)->comment(comment);
1107 }
1108
1109 WTF_ATTRIBUTE_PRINTF(2, 3)
1110 static void warningHandler(void* closure, const char* message, ...)
1111 {
1112     va_list args;
1113     va_start(args, message);
1114     getParser(closure)->error(XMLErrors::warning, message, args);
1115     va_end(args);
1116 }
1117
1118 WTF_ATTRIBUTE_PRINTF(2, 3)
1119 static void fatalErrorHandler(void* closure, const char* message, ...)
1120 {
1121     va_list args;
1122     va_start(args, message);
1123     getParser(closure)->error(XMLErrors::fatal, message, args);
1124     va_end(args);
1125 }
1126
1127 WTF_ATTRIBUTE_PRINTF(2, 3)
1128 static void normalErrorHandler(void* closure, const char* message, ...)
1129 {
1130     va_list args;
1131     va_start(args, message);
1132     getParser(closure)->error(XMLErrors::nonFatal, message, args);
1133     va_end(args);
1134 }
1135
1136 // Using a static entity and marking it XML_INTERNAL_PREDEFINED_ENTITY is
1137 // a hack to avoid malloc/free. Using a global variable like this could cause trouble
1138 // if libxml implementation details were to change
1139 static xmlChar sharedXHTMLEntityResult[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
1140
1141 static xmlEntityPtr sharedXHTMLEntity()
1142 {
1143     static xmlEntity entity;
1144     if (!entity.type) {
1145         entity.type = XML_ENTITY_DECL;
1146         entity.orig = sharedXHTMLEntityResult;
1147         entity.content = sharedXHTMLEntityResult;
1148         entity.etype = XML_INTERNAL_PREDEFINED_ENTITY;
1149     }
1150     return &entity;
1151 }
1152
1153 static size_t convertUTF16EntityToUTF8(const UChar* utf16Entity, size_t numberOfCodeUnits, char* target, size_t targetSize)
1154 {
1155     const char* originalTarget = target;
1156     auto conversionResult = WTF::Unicode::convertUTF16ToUTF8(&utf16Entity, utf16Entity + numberOfCodeUnits, &target, target + targetSize);
1157     if (conversionResult != WTF::Unicode::conversionOK)
1158         return 0;
1159
1160     // Even though we must pass the length, libxml expects the entity string to be null terminated.
1161     ASSERT(target >= originalTarget + 1);
1162     *target = '\0';
1163     return target - originalTarget;
1164 }
1165
1166 static xmlEntityPtr getXHTMLEntity(const xmlChar* name)
1167 {
1168     UChar utf16DecodedEntity[4];
1169     size_t numberOfCodeUnits = decodeNamedEntityToUCharArray(reinterpret_cast<const char*>(name), utf16DecodedEntity);
1170     if (!numberOfCodeUnits)
1171         return 0;
1172
1173     ASSERT(numberOfCodeUnits <= 4);
1174     size_t entityLengthInUTF8 = convertUTF16EntityToUTF8(utf16DecodedEntity, numberOfCodeUnits,
1175         reinterpret_cast<char*>(sharedXHTMLEntityResult), WTF_ARRAY_LENGTH(sharedXHTMLEntityResult));
1176     if (!entityLengthInUTF8)
1177         return 0;
1178
1179     xmlEntityPtr entity = sharedXHTMLEntity();
1180     entity->length = entityLengthInUTF8;
1181     entity->name = name;
1182     return entity;
1183 }
1184
1185 static void entityDeclarationHandler(void* closure, const xmlChar* name, int type, const xmlChar* publicId, const xmlChar* systemId, xmlChar* content)
1186 {
1187     // Prevent the next call to getEntityHandler() to record the entity expansion depth.
1188     // We're parsing the entity declaration, so there's no need to record anything.
1189     // We only need to record the depth, if we're actually expanding the entity, when it's referenced.
1190     if (hackAroundLibXMLEntityParsingBug())
1191         getParser(closure)->setIsParsingEntityDeclaration(true);
1192     xmlSAX2EntityDecl(closure, name, type, publicId, systemId, content);
1193 }
1194
1195 static xmlEntityPtr getEntityHandler(void* closure, const xmlChar* name)
1196 {
1197     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1198
1199     XMLDocumentParser* parser = getParser(closure);
1200     if (hackAroundLibXMLEntityParsingBug()) {
1201         if (parser->isParsingEntityDeclaration()) {
1202             // We're parsing the entity declarations (not an entity reference), no need to do anything special.
1203             parser->setIsParsingEntityDeclaration(false);
1204             ASSERT(parser->depthTriggeringEntityExpansion() == -1);
1205         } else {
1206             // The entity will be used and eventually expanded. Record the current parser depth
1207             // so the next call to startElementNs() knows that the new element originates from
1208             // an entity declaration.
1209             parser->setDepthTriggeringEntityExpansion(ctxt->depth);
1210         }
1211     }
1212
1213     xmlEntityPtr ent = xmlGetPredefinedEntity(name);
1214     if (ent) {
1215         ent->etype = XML_INTERNAL_PREDEFINED_ENTITY;
1216         return ent;
1217     }
1218
1219     ent = xmlGetDocEntity(ctxt->myDoc, name);
1220     if (!ent && parser->isXHTMLDocument()) {
1221         ent = getXHTMLEntity(name);
1222         if (ent)
1223             ent->etype = XML_INTERNAL_GENERAL_ENTITY;
1224     }
1225
1226     return ent;
1227 }
1228
1229 static void startDocumentHandler(void* closure)
1230 {
1231     xmlParserCtxt* ctxt = static_cast<xmlParserCtxt*>(closure);
1232     switchToUTF16(ctxt);
1233     getParser(closure)->startDocument(ctxt->version, ctxt->encoding, ctxt->standalone);
1234     xmlSAX2StartDocument(closure);
1235 }
1236
1237 static void endDocumentHandler(void* closure)
1238 {
1239     getParser(closure)->endDocument();
1240     xmlSAX2EndDocument(closure);
1241 }
1242
1243 static void internalSubsetHandler(void* closure, const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID)
1244 {
1245     getParser(closure)->internalSubset(name, externalID, systemID);
1246     xmlSAX2InternalSubset(closure, name, externalID, systemID);
1247 }
1248
1249 static void externalSubsetHandler(void* closure, const xmlChar*, const xmlChar* externalId, const xmlChar*)
1250 {
1251     String extId = toString(externalId);
1252     if ((extId == "-//W3C//DTD XHTML 1.0 Transitional//EN")
1253         || (extId == "-//W3C//DTD XHTML 1.1//EN")
1254         || (extId == "-//W3C//DTD XHTML 1.0 Strict//EN")
1255         || (extId == "-//W3C//DTD XHTML 1.0 Frameset//EN")
1256         || (extId == "-//W3C//DTD XHTML Basic 1.0//EN")
1257         || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN")
1258         || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN")
1259         || (extId == "-//W3C//DTD MathML 2.0//EN")
1260         || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.0//EN")
1261         || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.1//EN")
1262         || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.2//EN"))
1263         getParser(closure)->setIsXHTMLDocument(true); // controls if we replace entities or not.
1264 }
1265
1266 static void ignorableWhitespaceHandler(void*, const xmlChar*, int)
1267 {
1268     // nothing to do, but we need this to work around a crasher
1269     // http://bugzilla.gnome.org/show_bug.cgi?id=172255
1270     // http://bugs.webkit.org/show_bug.cgi?id=5792
1271 }
1272
1273 void XMLDocumentParser::initializeParserContext(const CString& chunk)
1274 {
1275     xmlSAXHandler sax;
1276     memset(&sax, 0, sizeof(sax));
1277
1278     sax.error = normalErrorHandler;
1279     sax.fatalError = fatalErrorHandler;
1280     sax.characters = charactersHandler;
1281     sax.processingInstruction = processingInstructionHandler;
1282     sax.cdataBlock = cdataBlockHandler;
1283     sax.comment = commentHandler;
1284     sax.warning = warningHandler;
1285     sax.startElementNs = startElementNsHandler;
1286     sax.endElementNs = endElementNsHandler;
1287     sax.getEntity = getEntityHandler;
1288     sax.startDocument = startDocumentHandler;
1289     sax.endDocument = endDocumentHandler;
1290     sax.internalSubset = internalSubsetHandler;
1291     sax.externalSubset = externalSubsetHandler;
1292     sax.ignorableWhitespace = ignorableWhitespaceHandler;
1293     sax.entityDecl = entityDeclarationHandler;
1294     sax.initialized = XML_SAX2_MAGIC;
1295     DocumentParser::startParsing();
1296     m_sawError = false;
1297     m_sawCSS = false;
1298     m_sawXSLTransform = false;
1299     m_sawFirstElement = false;
1300
1301     XMLDocumentParserScope scope(&document()->cachedResourceLoader());
1302     if (m_parsingFragment)
1303         m_context = XMLParserContext::createMemoryParser(&sax, this, chunk);
1304     else {
1305         ASSERT(!chunk.data());
1306         m_context = XMLParserContext::createStringParser(&sax, this);
1307     }
1308 }
1309
1310 void XMLDocumentParser::doEnd()
1311 {
1312     if (!isStopped()) {
1313         if (m_context) {
1314             // Tell libxml we're done.
1315             {
1316                 XMLDocumentParserScope scope(&document()->cachedResourceLoader());
1317                 xmlParseChunk(context(), 0, 0, 1);
1318             }
1319
1320             m_context = nullptr;
1321         }
1322     }
1323
1324 #if ENABLE(XSLT)
1325     bool xmlViewerMode = !m_sawError && !m_sawCSS && !m_sawXSLTransform && shouldRenderInXMLTreeViewerMode(*document());
1326     if (xmlViewerMode) {
1327         XMLTreeViewer xmlTreeViewer(*document());
1328         xmlTreeViewer.transformDocumentToTreeView();
1329     } else if (m_sawXSLTransform) {
1330         void* doc = xmlDocPtrForString(document()->cachedResourceLoader(), m_originalSourceForTransform.toString(), document()->url().string());
1331         document()->setTransformSource(std::make_unique<TransformSource>(doc));
1332
1333         document()->setParsing(false); // Make the document think it's done, so it will apply XSL stylesheets.
1334         document()->styleScope().didChangeActiveStyleSheetCandidates();
1335
1336         // styleResolverChanged() call can detach the parser and null out its document.
1337         // In that case, we just bail out.
1338         if (isDetached())
1339             return;
1340
1341         document()->setParsing(true);
1342         DocumentParser::stopParsing();
1343     }
1344 #endif
1345 }
1346
1347 #if ENABLE(XSLT)
1348 static inline const char* nativeEndianUTF16Encoding()
1349 {
1350     const UChar BOM = 0xFEFF;
1351     const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
1352     return BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE";
1353 }
1354
1355 void* xmlDocPtrForString(CachedResourceLoader& cachedResourceLoader, const String& source, const String& url)
1356 {
1357     if (source.isEmpty())
1358         return nullptr;
1359
1360     // Parse in a single chunk into an xmlDocPtr
1361     // FIXME: Hook up error handlers so that a failure to parse the main document results in
1362     // good error messages.
1363
1364     const bool is8Bit = source.is8Bit();
1365     const char* characters = is8Bit ? reinterpret_cast<const char*>(source.characters8()) : reinterpret_cast<const char*>(source.characters16());
1366     size_t sizeInBytes = source.length() * (is8Bit ? sizeof(LChar) : sizeof(UChar));
1367     const char* encoding = is8Bit ? "iso-8859-1" : nativeEndianUTF16Encoding();
1368
1369     XMLDocumentParserScope scope(&cachedResourceLoader, errorFunc);
1370     return xmlReadMemory(characters, sizeInBytes, url.latin1().data(), encoding, XSLT_PARSE_OPTIONS);
1371 }
1372 #endif
1373
1374 TextPosition XMLDocumentParser::textPosition() const
1375 {
1376     xmlParserCtxtPtr context = this->context();
1377     if (!context)
1378         return TextPosition();
1379     return TextPosition(OrdinalNumber::fromOneBasedInt(context->input->line),
1380                         OrdinalNumber::fromOneBasedInt(context->input->col));
1381 }
1382
1383 bool XMLDocumentParser::shouldAssociateConsoleMessagesWithTextPosition() const
1384 {
1385     return !m_parserPaused && !m_requestingScript;
1386 }
1387
1388 void XMLDocumentParser::stopParsing()
1389 {
1390     DocumentParser::stopParsing();
1391     if (context())
1392         xmlStopParser(context());
1393 }
1394
1395 void XMLDocumentParser::resumeParsing()
1396 {
1397     ASSERT(!isDetached());
1398     ASSERT(m_parserPaused);
1399
1400     m_parserPaused = false;
1401
1402     // First, execute any pending callbacks
1403     while (!m_pendingCallbacks->isEmpty()) {
1404         m_pendingCallbacks->callAndRemoveFirstCallback(this);
1405
1406         // A callback paused the parser
1407         if (m_parserPaused)
1408             return;
1409     }
1410
1411     // There is normally only one string left, so toString() shouldn't copy.
1412     // In any case, the XML parser runs on the main thread and it's OK if
1413     // the passed string has more than one reference.
1414     auto rest = m_pendingSrc.toString();
1415     m_pendingSrc.clear();
1416     append(rest.impl());
1417
1418     // Finally, if finish() has been called and write() didn't result
1419     // in any further callbacks being queued, call end()
1420     if (m_finishCalled && m_pendingCallbacks->isEmpty())
1421         end();
1422 }
1423
1424 bool XMLDocumentParser::appendFragmentSource(const String& chunk)
1425 {
1426     ASSERT(!m_context);
1427     ASSERT(m_parsingFragment);
1428
1429     CString chunkAsUtf8 = chunk.utf8();
1430     
1431     // libxml2 takes an int for a length, and therefore can't handle XML chunks larger than 2 GiB.
1432     if (chunkAsUtf8.length() > INT_MAX)
1433         return false;
1434
1435     initializeParserContext(chunkAsUtf8);
1436     xmlParseContent(context());
1437     endDocument(); // Close any open text nodes.
1438
1439     // FIXME: If this code is actually needed, it should probably move to finish()
1440     // XMLDocumentParserQt has a similar check (m_stream.error() == QXmlStreamReader::PrematureEndOfDocumentError) in doEnd().
1441     // Check if all the chunk has been processed.
1442     long bytesProcessed = xmlByteConsumed(context());
1443     if (bytesProcessed == -1 || ((unsigned long)bytesProcessed) != chunkAsUtf8.length()) {
1444         // FIXME: I don't believe we can hit this case without also having seen an error or a null byte.
1445         // If we hit this ASSERT, we've found a test case which demonstrates the need for this code.
1446         ASSERT(m_sawError || (bytesProcessed >= 0 && !chunkAsUtf8.data()[bytesProcessed]));
1447         return false;
1448     }
1449
1450     // No error if the chunk is well formed or it is not but we have no error.
1451     return context()->wellFormed || !xmlCtxtGetLastError(context());
1452 }
1453
1454 // --------------------------------
1455
1456 struct AttributeParseState {
1457     HashMap<String, String> attributes;
1458     bool gotAttributes;
1459 };
1460
1461 static void attributesStartElementNsHandler(void* closure, const xmlChar* xmlLocalName, const xmlChar* /*xmlPrefix*/, const xmlChar* /*xmlURI*/, int /*numNamespaces*/, const xmlChar** /*namespaces*/, int numAttributes, int /*numDefaulted*/, const xmlChar** libxmlAttributes)
1462 {
1463     if (strcmp(reinterpret_cast<const char*>(xmlLocalName), "attrs") != 0)
1464         return;
1465
1466     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1467     AttributeParseState* state = static_cast<AttributeParseState*>(ctxt->_private);
1468
1469     state->gotAttributes = true;
1470
1471     xmlSAX2Attributes* attributes = reinterpret_cast<xmlSAX2Attributes*>(libxmlAttributes);
1472     for (int i = 0; i < numAttributes; i++) {
1473         String attrLocalName = toString(attributes[i].localname);
1474         int valueLength = (int) (attributes[i].end - attributes[i].value);
1475         String attrValue = toString(attributes[i].value, valueLength);
1476         String attrPrefix = toString(attributes[i].prefix);
1477         String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName;
1478
1479         state->attributes.set(attrQName, attrValue);
1480     }
1481 }
1482
1483 HashMap<String, String> parseAttributes(const String& string, bool& attrsOK)
1484 {
1485     String parseString = "<?xml version=\"1.0\"?><attrs " + string + " />";
1486
1487     AttributeParseState state;
1488     state.gotAttributes = false;
1489
1490     xmlSAXHandler sax;
1491     memset(&sax, 0, sizeof(sax));
1492     sax.startElementNs = attributesStartElementNsHandler;
1493     sax.initialized = XML_SAX2_MAGIC;
1494
1495     RefPtr<XMLParserContext> parser = XMLParserContext::createStringParser(&sax, &state);
1496
1497     // FIXME: Can we parse 8-bit strings directly as Latin-1 instead of upconverting to UTF-16?
1498     xmlParseChunk(parser->context(), reinterpret_cast<const char*>(StringView(parseString).upconvertedCharacters().get()), parseString.length() * sizeof(UChar), 1);
1499
1500     attrsOK = state.gotAttributes;
1501     return WTFMove(state.attributes);
1502 }
1503
1504 }