1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsExpatDriver.h"
7 #include "nsCOMPtr.h"
8 #include "nsParserCIID.h"
9 #include "CParserContext.h"
10 #include "nsIExpatSink.h"
11 #include "nsIContentSink.h"
12 #include "nsParserMsgUtils.h"
13 #include "nsIURL.h"
14 #include "nsIUnicharInputStream.h"
15 #include "nsIProtocolHandler.h"
16 #include "nsNetUtil.h"
17 #include "nsTextFormatter.h"
18 #include "nsDirectoryServiceDefs.h"
19 #include "nsCRT.h"
20 #include "nsIConsoleService.h"
21 #include "nsIScriptError.h"
22 #include "nsIContentPolicy.h"
23 #include "nsContentPolicyUtils.h"
24 #include "nsError.h"
25 #include "nsXPCOMCIDInternal.h"
26 #include "nsUnicharInputStream.h"
27 #include "nsContentUtils.h"
28 #include "mozilla/BasePrincipal.h"
29 #include "mozilla/IntegerTypeTraits.h"
30 #include "mozilla/NullPrincipal.h"
31
32 #include "mozilla/Logging.h"
33
34 using mozilla::fallible;
35 using mozilla::LogLevel;
36 using mozilla::MakeStringSpan;
37 using mozilla::dom::Document;
38
39 #define kExpatSeparatorChar 0xFFFF
40
41 static const char16_t kUTF16[] = {'U', 'T', 'F', '-', '1', '6', '\0'};
42
43 static mozilla::LazyLogModule gExpatDriverLog("expatdriver");
44
45 // Use the same maximum tree depth as Chromium (see
46 // https://chromium.googlesource.com/chromium/src/+/f464165c1dedff1c955d3c051c5a9a1c6a0e8f6b/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp#85).
47 static const uint16_t sMaxXMLTreeDepth = 5000;
48
49 /***************************** EXPAT CALL BACKS ******************************/
50 // The callback handlers that get called from the expat parser.
51
Driver_HandleXMLDeclaration(void * aUserData,const XML_Char * aVersion,const XML_Char * aEncoding,int aStandalone)52 static void Driver_HandleXMLDeclaration(void* aUserData,
53 const XML_Char* aVersion,
54 const XML_Char* aEncoding,
55 int aStandalone) {
56 NS_ASSERTION(aUserData, "expat driver should exist");
57 if (aUserData) {
58 nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
59 driver->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
60 }
61 }
62
Driver_HandleCharacterData(void * aUserData,const XML_Char * aData,int aLength)63 static void Driver_HandleCharacterData(void* aUserData, const XML_Char* aData,
64 int aLength) {
65 NS_ASSERTION(aUserData, "expat driver should exist");
66 if (aUserData) {
67 nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
68 driver->HandleCharacterData(aData, uint32_t(aLength));
69 }
70 }
71
Driver_HandleComment(void * aUserData,const XML_Char * aName)72 static void Driver_HandleComment(void* aUserData, const XML_Char* aName) {
73 NS_ASSERTION(aUserData, "expat driver should exist");
74 if (aUserData) {
75 static_cast<nsExpatDriver*>(aUserData)->HandleComment(aName);
76 }
77 }
78
Driver_HandleProcessingInstruction(void * aUserData,const XML_Char * aTarget,const XML_Char * aData)79 static void Driver_HandleProcessingInstruction(void* aUserData,
80 const XML_Char* aTarget,
81 const XML_Char* aData) {
82 NS_ASSERTION(aUserData, "expat driver should exist");
83 if (aUserData) {
84 nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
85 driver->HandleProcessingInstruction(aTarget, aData);
86 }
87 }
88
Driver_HandleDefault(void * aUserData,const XML_Char * aData,int aLength)89 static void Driver_HandleDefault(void* aUserData, const XML_Char* aData,
90 int aLength) {
91 NS_ASSERTION(aUserData, "expat driver should exist");
92 if (aUserData) {
93 nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
94 driver->HandleDefault(aData, uint32_t(aLength));
95 }
96 }
97
Driver_HandleStartCdataSection(void * aUserData)98 static void Driver_HandleStartCdataSection(void* aUserData) {
99 NS_ASSERTION(aUserData, "expat driver should exist");
100 if (aUserData) {
101 static_cast<nsExpatDriver*>(aUserData)->HandleStartCdataSection();
102 }
103 }
104
Driver_HandleEndCdataSection(void * aUserData)105 static void Driver_HandleEndCdataSection(void* aUserData) {
106 NS_ASSERTION(aUserData, "expat driver should exist");
107 if (aUserData) {
108 static_cast<nsExpatDriver*>(aUserData)->HandleEndCdataSection();
109 }
110 }
111
Driver_HandleStartDoctypeDecl(void * aUserData,const XML_Char * aDoctypeName,const XML_Char * aSysid,const XML_Char * aPubid,int aHasInternalSubset)112 static void Driver_HandleStartDoctypeDecl(void* aUserData,
113 const XML_Char* aDoctypeName,
114 const XML_Char* aSysid,
115 const XML_Char* aPubid,
116 int aHasInternalSubset) {
117 NS_ASSERTION(aUserData, "expat driver should exist");
118 if (aUserData) {
119 static_cast<nsExpatDriver*>(aUserData)->HandleStartDoctypeDecl(
120 aDoctypeName, aSysid, aPubid, !!aHasInternalSubset);
121 }
122 }
123
Driver_HandleEndDoctypeDecl(void * aUserData)124 static void Driver_HandleEndDoctypeDecl(void* aUserData) {
125 NS_ASSERTION(aUserData, "expat driver should exist");
126 if (aUserData) {
127 static_cast<nsExpatDriver*>(aUserData)->HandleEndDoctypeDecl();
128 }
129 }
130
Driver_HandleExternalEntityRef(void * aExternalEntityRefHandler,const XML_Char * aOpenEntityNames,const XML_Char * aBase,const XML_Char * aSystemId,const XML_Char * aPublicId)131 static int Driver_HandleExternalEntityRef(void* aExternalEntityRefHandler,
132 const XML_Char* aOpenEntityNames,
133 const XML_Char* aBase,
134 const XML_Char* aSystemId,
135 const XML_Char* aPublicId) {
136 NS_ASSERTION(aExternalEntityRefHandler, "expat driver should exist");
137 if (!aExternalEntityRefHandler) {
138 return 1;
139 }
140
141 nsExpatDriver* driver =
142 static_cast<nsExpatDriver*>(aExternalEntityRefHandler);
143
144 return driver->HandleExternalEntityRef(aOpenEntityNames, aBase, aSystemId,
145 aPublicId);
146 }
147
148 /***************************** END CALL BACKS ********************************/
149
150 /***************************** CATALOG UTILS *********************************/
151
152 // Initially added for bug 113400 to switch from the remote "XHTML 1.0 plus
153 // MathML 2.0" DTD to the the lightweight customized version that Mozilla uses.
154 // Since Mozilla is not validating, no need to fetch a *huge* file at each
155 // click.
156 // XXX The cleanest solution here would be to fix Bug 98413: Implement XML
157 // Catalogs.
158 struct nsCatalogData {
159 const char* mPublicID;
160 const char* mLocalDTD;
161 const char* mAgentSheet;
162 };
163
164 // The order of this table is guestimated to be in the optimum order
165 static const nsCatalogData kCatalogTable[] = {
166 {"-//W3C//DTD XHTML 1.0 Transitional//EN", "htmlmathml-f.ent", nullptr},
167 {"-//W3C//DTD XHTML 1.1//EN", "htmlmathml-f.ent", nullptr},
168 {"-//W3C//DTD XHTML 1.0 Strict//EN", "htmlmathml-f.ent", nullptr},
169 {"-//W3C//DTD XHTML 1.0 Frameset//EN", "htmlmathml-f.ent", nullptr},
170 {"-//W3C//DTD XHTML Basic 1.0//EN", "htmlmathml-f.ent", nullptr},
171 {"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN", "htmlmathml-f.ent", nullptr},
172 {"-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN",
173 "htmlmathml-f.ent", nullptr},
174 {"-//W3C//DTD MathML 2.0//EN", "htmlmathml-f.ent", nullptr},
175 {"-//WAPFORUM//DTD XHTML Mobile 1.0//EN", "htmlmathml-f.ent", nullptr},
176 {nullptr, nullptr, nullptr}};
177
LookupCatalogData(const char16_t * aPublicID)178 static const nsCatalogData* LookupCatalogData(const char16_t* aPublicID) {
179 nsDependentString publicID(aPublicID);
180
181 // linear search for now since the number of entries is going to
182 // be negligible, and the fix for bug 98413 would get rid of this
183 // code anyway
184 const nsCatalogData* data = kCatalogTable;
185 while (data->mPublicID) {
186 if (publicID.EqualsASCII(data->mPublicID)) {
187 return data;
188 }
189 ++data;
190 }
191
192 return nullptr;
193 }
194
195 // This function provides a resource URI to a local DTD
196 // in resource://gre/res/dtd/ which may or may not exist.
197 // If aCatalogData is provided, it is used to remap the
198 // DTD instead of taking the filename from the URI. aDTD
199 // may be null in some cases that are relying on
200 // aCatalogData working for them.
GetLocalDTDURI(const nsCatalogData * aCatalogData,nsIURI * aDTD,nsIURI ** aResult)201 static void GetLocalDTDURI(const nsCatalogData* aCatalogData, nsIURI* aDTD,
202 nsIURI** aResult) {
203 nsAutoCString fileName;
204 if (aCatalogData) {
205 // remap the DTD to a known local DTD
206 fileName.Assign(aCatalogData->mLocalDTD);
207 }
208
209 if (fileName.IsEmpty()) {
210 // Try to see if the user has installed the DTD file -- we extract the
211 // filename.ext of the DTD here. Hence, for any DTD for which we have
212 // no predefined mapping, users just have to copy the DTD file to our
213 // special DTD directory and it will be picked.
214 nsCOMPtr<nsIURL> dtdURL = do_QueryInterface(aDTD);
215 if (!dtdURL) {
216 // Not a URL with a filename, or maybe it was null. Either way, nothing
217 // else we can do here.
218 return;
219 }
220
221 dtdURL->GetFileName(fileName);
222 if (fileName.IsEmpty()) {
223 return;
224 }
225 }
226
227 nsAutoCString respath("resource://gre/res/dtd/");
228 respath += fileName;
229 NS_NewURI(aResult, respath);
230 }
231
232 /***************************** END CATALOG UTILS *****************************/
233
234 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsExpatDriver)
NS_INTERFACE_MAP_ENTRY(nsITokenizer)235 NS_INTERFACE_MAP_ENTRY(nsITokenizer)
236 NS_INTERFACE_MAP_ENTRY(nsIDTD)
237 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDTD)
238 NS_INTERFACE_MAP_END
239
240 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsExpatDriver)
241 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsExpatDriver)
242
243 NS_IMPL_CYCLE_COLLECTION(nsExpatDriver, mSink)
244
245 nsExpatDriver::nsExpatDriver()
246 : mExpatParser(nullptr),
247 mInCData(false),
248 mInInternalSubset(false),
249 mInExternalDTD(false),
250 mMadeFinalCallToExpat(false),
251 mIsFinalChunk(false),
252 mInternalState(NS_OK),
253 mExpatBuffered(0),
254 mTagDepth(0),
255 mCatalogData(nullptr),
256 mInnerWindowID(0) {}
257
~nsExpatDriver()258 nsExpatDriver::~nsExpatDriver() {
259 if (mExpatParser) {
260 XML_ParserFree(mExpatParser);
261 }
262 }
263
264 /* static */
HandleStartElement(void * aUserData,const char16_t * aName,const char16_t ** aAtts)265 void nsExpatDriver::HandleStartElement(void* aUserData, const char16_t* aName,
266 const char16_t** aAtts) {
267 nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
268
269 NS_ASSERTION(self->mSink, "content sink not found!");
270
271 // Calculate the total number of elements in aAtts.
272 // XML_GetSpecifiedAttributeCount will only give us the number of specified
273 // attrs (twice that number, actually), so we have to check for default attrs
274 // ourselves.
275 uint32_t attrArrayLength;
276 for (attrArrayLength = XML_GetSpecifiedAttributeCount(self->mExpatParser);
277 aAtts[attrArrayLength]; attrArrayLength += 2) {
278 // Just looping till we find out what the length is
279 }
280
281 if (self->mSink) {
282 // We store the tagdepth in a PRUint16, so make sure the limit fits in a
283 // PRUint16.
284 static_assert(
285 sMaxXMLTreeDepth <=
286 std::numeric_limits<decltype(nsExpatDriver::mTagDepth)>::max());
287
288 if (++self->mTagDepth > sMaxXMLTreeDepth) {
289 self->MaybeStopParser(NS_ERROR_HTMLPARSER_HIERARCHYTOODEEP);
290 return;
291 }
292
293 nsresult rv = self->mSink->HandleStartElement(
294 aName, aAtts, attrArrayLength,
295 XML_GetCurrentLineNumber(self->mExpatParser),
296 XML_GetCurrentColumnNumber(self->mExpatParser));
297 self->MaybeStopParser(rv);
298 }
299 }
300
301 /* static */
HandleStartElementForSystemPrincipal(void * aUserData,const char16_t * aName,const char16_t ** aAtts)302 void nsExpatDriver::HandleStartElementForSystemPrincipal(
303 void* aUserData, const char16_t* aName, const char16_t** aAtts) {
304 nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
305
306 if (!MOZ_XML_ProcessingEntityValue(self->mExpatParser)) {
307 HandleStartElement(aUserData, aName, aAtts);
308 } else {
309 nsCOMPtr<Document> doc =
310 do_QueryInterface(self->mOriginalSink->GetTarget());
311
312 // Adjust the column number so that it is one based rather than zero based.
313 uint32_t colNumber = XML_GetCurrentColumnNumber(self->mExpatParser) + 1;
314 uint32_t lineNumber = XML_GetCurrentLineNumber(self->mExpatParser);
315
316 int32_t nameSpaceID;
317 RefPtr<nsAtom> prefix, localName;
318 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
319 getter_AddRefs(localName), &nameSpaceID);
320
321 nsAutoString error;
322 error.AppendLiteral("Ignoring element <");
323 if (prefix) {
324 error.Append(prefix->GetUTF16String());
325 error.Append(':');
326 }
327 error.Append(localName->GetUTF16String());
328 error.AppendLiteral("> created from entity value.");
329
330 nsContentUtils::ReportToConsoleNonLocalized(
331 error, nsIScriptError::warningFlag, NS_LITERAL_CSTRING("XML Document"),
332 doc, nullptr, EmptyString(), lineNumber, colNumber);
333 }
334 }
335
336 /* static */
HandleEndElement(void * aUserData,const char16_t * aName)337 void nsExpatDriver::HandleEndElement(void* aUserData, const char16_t* aName) {
338 nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
339
340 NS_ASSERTION(self->mSink, "content sink not found!");
341 NS_ASSERTION(self->mInternalState != NS_ERROR_HTMLPARSER_BLOCK,
342 "Shouldn't block from HandleStartElement.");
343
344 if (self->mSink && self->mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
345 nsresult rv = self->mSink->HandleEndElement(aName);
346 --self->mTagDepth;
347 self->MaybeStopParser(rv);
348 }
349 }
350
351 /* static */
HandleEndElementForSystemPrincipal(void * aUserData,const char16_t * aName)352 void nsExpatDriver::HandleEndElementForSystemPrincipal(void* aUserData,
353 const char16_t* aName) {
354 nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
355
356 if (!MOZ_XML_ProcessingEntityValue(self->mExpatParser)) {
357 HandleEndElement(aUserData, aName);
358 }
359 }
360
HandleCharacterData(const char16_t * aValue,const uint32_t aLength)361 nsresult nsExpatDriver::HandleCharacterData(const char16_t* aValue,
362 const uint32_t aLength) {
363 NS_ASSERTION(mSink, "content sink not found!");
364
365 if (mInCData) {
366 if (!mCDataText.Append(aValue, aLength, fallible)) {
367 MaybeStopParser(NS_ERROR_OUT_OF_MEMORY);
368 }
369 } else if (mSink) {
370 nsresult rv = mSink->HandleCharacterData(aValue, aLength);
371 MaybeStopParser(rv);
372 }
373
374 return NS_OK;
375 }
376
HandleComment(const char16_t * aValue)377 nsresult nsExpatDriver::HandleComment(const char16_t* aValue) {
378 NS_ASSERTION(mSink, "content sink not found!");
379
380 if (mInExternalDTD) {
381 // Ignore comments from external DTDs
382 return NS_OK;
383 }
384
385 if (mInInternalSubset) {
386 mInternalSubset.AppendLiteral("<!--");
387 mInternalSubset.Append(aValue);
388 mInternalSubset.AppendLiteral("-->");
389 } else if (mSink) {
390 nsresult rv = mSink->HandleComment(aValue);
391 MaybeStopParser(rv);
392 }
393
394 return NS_OK;
395 }
396
HandleProcessingInstruction(const char16_t * aTarget,const char16_t * aData)397 nsresult nsExpatDriver::HandleProcessingInstruction(const char16_t* aTarget,
398 const char16_t* aData) {
399 NS_ASSERTION(mSink, "content sink not found!");
400
401 if (mInExternalDTD) {
402 // Ignore PIs in external DTDs for now. Eventually we want to
403 // pass them to the sink in a way that doesn't put them in the DOM
404 return NS_OK;
405 }
406
407 if (mInInternalSubset) {
408 mInternalSubset.AppendLiteral("<?");
409 mInternalSubset.Append(aTarget);
410 mInternalSubset.Append(' ');
411 mInternalSubset.Append(aData);
412 mInternalSubset.AppendLiteral("?>");
413 } else if (mSink) {
414 nsresult rv = mSink->HandleProcessingInstruction(aTarget, aData);
415 MaybeStopParser(rv);
416 }
417
418 return NS_OK;
419 }
420
HandleXMLDeclaration(const char16_t * aVersion,const char16_t * aEncoding,int32_t aStandalone)421 nsresult nsExpatDriver::HandleXMLDeclaration(const char16_t* aVersion,
422 const char16_t* aEncoding,
423 int32_t aStandalone) {
424 if (mSink) {
425 nsresult rv = mSink->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
426 MaybeStopParser(rv);
427 }
428
429 return NS_OK;
430 }
431
HandleDefault(const char16_t * aValue,const uint32_t aLength)432 nsresult nsExpatDriver::HandleDefault(const char16_t* aValue,
433 const uint32_t aLength) {
434 NS_ASSERTION(mSink, "content sink not found!");
435
436 if (mInExternalDTD) {
437 // Ignore newlines in external DTDs
438 return NS_OK;
439 }
440
441 if (mInInternalSubset) {
442 mInternalSubset.Append(aValue, aLength);
443 } else if (mSink) {
444 uint32_t i;
445 nsresult rv = mInternalState;
446 for (i = 0; i < aLength && NS_SUCCEEDED(rv); ++i) {
447 if (aValue[i] == '\n' || aValue[i] == '\r') {
448 rv = mSink->HandleCharacterData(&aValue[i], 1);
449 }
450 }
451 MaybeStopParser(rv);
452 }
453
454 return NS_OK;
455 }
456
HandleStartCdataSection()457 nsresult nsExpatDriver::HandleStartCdataSection() {
458 mInCData = true;
459
460 return NS_OK;
461 }
462
HandleEndCdataSection()463 nsresult nsExpatDriver::HandleEndCdataSection() {
464 NS_ASSERTION(mSink, "content sink not found!");
465
466 mInCData = false;
467 if (mSink) {
468 nsresult rv =
469 mSink->HandleCDataSection(mCDataText.get(), mCDataText.Length());
470 MaybeStopParser(rv);
471 }
472 mCDataText.Truncate();
473
474 return NS_OK;
475 }
476
HandleStartDoctypeDecl(const char16_t * aDoctypeName,const char16_t * aSysid,const char16_t * aPubid,bool aHasInternalSubset)477 nsresult nsExpatDriver::HandleStartDoctypeDecl(const char16_t* aDoctypeName,
478 const char16_t* aSysid,
479 const char16_t* aPubid,
480 bool aHasInternalSubset) {
481 mDoctypeName = aDoctypeName;
482 mSystemID = aSysid;
483 mPublicID = aPubid;
484
485 if (aHasInternalSubset) {
486 // Consuming a huge internal subset translates to numerous
487 // allocations. In an effort to avoid too many allocations
488 // setting mInternalSubset's capacity to be 1K ( just a guesstimate! ).
489 mInInternalSubset = true;
490 mInternalSubset.SetCapacity(1024);
491 } else {
492 // Distinguish missing internal subset from an empty one
493 mInternalSubset.SetIsVoid(true);
494 }
495
496 return NS_OK;
497 }
498
HandleEndDoctypeDecl()499 nsresult nsExpatDriver::HandleEndDoctypeDecl() {
500 NS_ASSERTION(mSink, "content sink not found!");
501
502 mInInternalSubset = false;
503
504 if (mSink) {
505 // let the sink know any additional knowledge that we have about the
506 // document (currently, from bug 124570, we only expect to pass additional
507 // agent sheets needed to layout the XML vocabulary of the document)
508 nsCOMPtr<nsIURI> data;
509 #if 0
510 if (mCatalogData && mCatalogData->mAgentSheet) {
511 NS_NewURI(getter_AddRefs(data), mCatalogData->mAgentSheet);
512 }
513 #endif
514
515 // The unused support for "catalog style sheets" was removed. It doesn't
516 // look like we'll ever fix bug 98413 either.
517 MOZ_ASSERT(!mCatalogData || !mCatalogData->mAgentSheet,
518 "Need to add back support for catalog style sheets");
519
520 // Note: mInternalSubset already doesn't include the [] around it.
521 nsresult rv = mSink->HandleDoctypeDecl(mInternalSubset, mDoctypeName,
522 mSystemID, mPublicID, data);
523 MaybeStopParser(rv);
524 }
525
526 mInternalSubset.Truncate();
527
528 return NS_OK;
529 }
530
ExternalDTDStreamReaderFunc(nsIUnicharInputStream * aIn,void * aClosure,const char16_t * aFromSegment,uint32_t aToOffset,uint32_t aCount,uint32_t * aWriteCount)531 static nsresult ExternalDTDStreamReaderFunc(nsIUnicharInputStream* aIn,
532 void* aClosure,
533 const char16_t* aFromSegment,
534 uint32_t aToOffset, uint32_t aCount,
535 uint32_t* aWriteCount) {
536 // Pass the buffer to expat for parsing.
537 if (XML_Parse((XML_Parser)aClosure, (const char*)aFromSegment,
538 aCount * sizeof(char16_t), 0) == XML_STATUS_OK) {
539 *aWriteCount = aCount;
540
541 return NS_OK;
542 }
543
544 *aWriteCount = 0;
545
546 return NS_ERROR_FAILURE;
547 }
548
HandleExternalEntityRef(const char16_t * openEntityNames,const char16_t * base,const char16_t * systemId,const char16_t * publicId)549 int nsExpatDriver::HandleExternalEntityRef(const char16_t* openEntityNames,
550 const char16_t* base,
551 const char16_t* systemId,
552 const char16_t* publicId) {
553 if (mInInternalSubset && !mInExternalDTD && openEntityNames) {
554 mInternalSubset.Append(char16_t('%'));
555 mInternalSubset.Append(nsDependentString(openEntityNames));
556 mInternalSubset.Append(char16_t(';'));
557 }
558
559 // Load the external entity into a buffer.
560 nsCOMPtr<nsIInputStream> in;
561 nsAutoString absURL;
562 nsresult rv = OpenInputStreamFromExternalDTD(publicId, systemId, base,
563 getter_AddRefs(in), absURL);
564 if (NS_FAILED(rv)) {
565 #ifdef DEBUG
566 nsCString message("Failed to open external DTD: publicId \"");
567 AppendUTF16toUTF8(MakeStringSpan(publicId), message);
568 message += "\" systemId \"";
569 AppendUTF16toUTF8(MakeStringSpan(systemId), message);
570 message += "\" base \"";
571 AppendUTF16toUTF8(MakeStringSpan(base), message);
572 message += "\" URL \"";
573 AppendUTF16toUTF8(absURL, message);
574 message += "\"";
575 NS_WARNING(message.get());
576 #endif
577 return 1;
578 }
579
580 nsCOMPtr<nsIUnicharInputStream> uniIn;
581 rv = NS_NewUnicharInputStream(in, getter_AddRefs(uniIn));
582 NS_ENSURE_SUCCESS(rv, 1);
583
584 int result = 1;
585 if (uniIn) {
586 XML_Parser entParser =
587 XML_ExternalEntityParserCreate(mExpatParser, 0, kUTF16);
588 if (entParser) {
589 XML_SetBase(entParser, absURL.get());
590
591 mInExternalDTD = true;
592
593 uint32_t totalRead;
594 do {
595 rv = uniIn->ReadSegments(ExternalDTDStreamReaderFunc, entParser,
596 uint32_t(-1), &totalRead);
597 } while (NS_SUCCEEDED(rv) && totalRead > 0);
598
599 result = XML_Parse(entParser, nullptr, 0, 1);
600
601 mInExternalDTD = false;
602
603 XML_ParserFree(entParser);
604 }
605 }
606
607 return result;
608 }
609
OpenInputStreamFromExternalDTD(const char16_t * aFPIStr,const char16_t * aURLStr,const char16_t * aBaseURL,nsIInputStream ** aStream,nsAString & aAbsURL)610 nsresult nsExpatDriver::OpenInputStreamFromExternalDTD(const char16_t* aFPIStr,
611 const char16_t* aURLStr,
612 const char16_t* aBaseURL,
613 nsIInputStream** aStream,
614 nsAString& aAbsURL) {
615 nsCOMPtr<nsIURI> baseURI;
616 nsresult rv =
617 NS_NewURI(getter_AddRefs(baseURI), NS_ConvertUTF16toUTF8(aBaseURL));
618 NS_ENSURE_SUCCESS(rv, rv);
619
620 nsCOMPtr<nsIURI> uri;
621 rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(aURLStr), nullptr,
622 baseURI);
623 // Even if the URI is malformed (most likely because we have a
624 // non-hierarchical base URI and a relative DTD URI, with the latter
625 // being the normal XHTML DTD case), we can try to see whether we
626 // have catalog data for aFPIStr.
627 if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_MALFORMED_URI)) {
628 return rv;
629 }
630
631 // make sure the URI, if we have one, is allowed to be loaded in sync
632 bool isUIResource = false;
633 if (uri) {
634 rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_UI_RESOURCE,
635 &isUIResource);
636 NS_ENSURE_SUCCESS(rv, rv);
637 }
638
639 nsCOMPtr<nsIURI> localURI;
640 if (!isUIResource) {
641 // Check to see if we can map the DTD to a known local DTD, or if a DTD
642 // file of the same name exists in the special DTD directory
643 if (aFPIStr) {
644 // see if the Formal Public Identifier (FPI) maps to a catalog entry
645 mCatalogData = LookupCatalogData(aFPIStr);
646 GetLocalDTDURI(mCatalogData, uri, getter_AddRefs(localURI));
647 }
648 if (!localURI) {
649 return NS_ERROR_NOT_IMPLEMENTED;
650 }
651 }
652
653 nsCOMPtr<nsIChannel> channel;
654 if (localURI) {
655 localURI.swap(uri);
656 rv = NS_NewChannel(getter_AddRefs(channel), uri,
657 nsContentUtils::GetSystemPrincipal(),
658 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
659 nsIContentPolicy::TYPE_DTD);
660 NS_ENSURE_SUCCESS(rv, rv);
661 } else {
662 NS_ASSERTION(
663 mSink == nsCOMPtr<nsIExpatSink>(do_QueryInterface(mOriginalSink)),
664 "In nsExpatDriver::OpenInputStreamFromExternalDTD: "
665 "mOriginalSink not the same object as mSink?");
666 nsContentPolicyType policyType = nsIContentPolicy::TYPE_INTERNAL_DTD;
667 if (mOriginalSink) {
668 nsCOMPtr<Document> doc;
669 doc = do_QueryInterface(mOriginalSink->GetTarget());
670 if (doc) {
671 if (doc->SkipDTDSecurityChecks()) {
672 policyType = nsIContentPolicy::TYPE_INTERNAL_FORCE_ALLOWED_DTD;
673 }
674 rv = NS_NewChannel(getter_AddRefs(channel), uri, doc,
675 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
676 nsILoadInfo::SEC_ALLOW_CHROME,
677 policyType);
678 NS_ENSURE_SUCCESS(rv, rv);
679 }
680 }
681 if (!channel) {
682 nsCOMPtr<nsIPrincipal> nullPrincipal =
683 mozilla::NullPrincipal::CreateWithoutOriginAttributes();
684 rv = NS_NewChannel(getter_AddRefs(channel), uri, nullPrincipal,
685 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
686 nsILoadInfo::SEC_ALLOW_CHROME,
687 policyType);
688 NS_ENSURE_SUCCESS(rv, rv);
689 }
690 }
691
692 nsAutoCString absURL;
693 rv = uri->GetSpec(absURL);
694 NS_ENSURE_SUCCESS(rv, rv);
695 CopyUTF8toUTF16(absURL, aAbsURL);
696
697 channel->SetContentType(NS_LITERAL_CSTRING("application/xml"));
698 return channel->Open(aStream);
699 }
700
CreateErrorText(const char16_t * aDescription,const char16_t * aSourceURL,const uint32_t aLineNumber,const uint32_t aColNumber,nsString & aErrorString,bool spoofEnglish)701 static nsresult CreateErrorText(const char16_t* aDescription,
702 const char16_t* aSourceURL,
703 const uint32_t aLineNumber,
704 const uint32_t aColNumber,
705 nsString& aErrorString, bool spoofEnglish) {
706 aErrorString.Truncate();
707
708 nsAutoString msg;
709 nsresult rv = nsParserMsgUtils::GetLocalizedStringByName(
710 spoofEnglish ? XMLPARSER_PROPERTIES_en_US : XMLPARSER_PROPERTIES,
711 "XMLParsingError", msg);
712 NS_ENSURE_SUCCESS(rv, rv);
713
714 // XML Parsing Error: %1$S\nLocation: %2$S\nLine Number %3$u, Column %4$u:
715 nsTextFormatter::ssprintf(aErrorString, msg.get(), aDescription, aSourceURL,
716 aLineNumber, aColNumber);
717 return NS_OK;
718 }
719
AppendErrorPointer(const int32_t aColNumber,const char16_t * aSourceLine,nsString & aSourceString)720 static nsresult AppendErrorPointer(const int32_t aColNumber,
721 const char16_t* aSourceLine,
722 nsString& aSourceString) {
723 aSourceString.Append(char16_t('\n'));
724
725 // Last character will be '^'.
726 int32_t last = aColNumber - 1;
727 int32_t i;
728 uint32_t minuses = 0;
729 for (i = 0; i < last; ++i) {
730 if (aSourceLine[i] == '\t') {
731 // Since this uses |white-space: pre;| a tab stop equals 8 spaces.
732 uint32_t add = 8 - (minuses % 8);
733 aSourceString.AppendASCII("--------", add);
734 minuses += add;
735 } else {
736 aSourceString.Append(char16_t('-'));
737 ++minuses;
738 }
739 }
740 aSourceString.Append(char16_t('^'));
741
742 return NS_OK;
743 }
744
HandleError()745 nsresult nsExpatDriver::HandleError() {
746 int32_t code = XML_GetErrorCode(mExpatParser);
747 NS_ASSERTION(code > XML_ERROR_NONE, "unexpected XML error code");
748
749 // Map Expat error code to an error string
750 // XXX Deal with error returns.
751 nsAutoString description;
752 nsCOMPtr<Document> doc;
753 if (mOriginalSink) {
754 doc = do_QueryInterface(mOriginalSink->GetTarget());
755 }
756 bool spoofEnglish =
757 nsContentUtils::SpoofLocaleEnglish() && (!doc || !doc->AllowsL10n());
758 nsParserMsgUtils::GetLocalizedStringByID(
759 spoofEnglish ? XMLPARSER_PROPERTIES_en_US : XMLPARSER_PROPERTIES, code,
760 description);
761
762 if (code == XML_ERROR_TAG_MISMATCH) {
763 /**
764 * Expat can send the following:
765 * localName
766 * namespaceURI<separator>localName
767 * namespaceURI<separator>localName<separator>prefix
768 *
769 * and we use 0xFFFF for the <separator>.
770 *
771 */
772 const char16_t* mismatch = MOZ_XML_GetMismatchedTag(mExpatParser);
773 const char16_t* uriEnd = nullptr;
774 const char16_t* nameEnd = nullptr;
775 const char16_t* pos;
776 for (pos = mismatch; *pos; ++pos) {
777 if (*pos == kExpatSeparatorChar) {
778 if (uriEnd) {
779 nameEnd = pos;
780 } else {
781 uriEnd = pos;
782 }
783 }
784 }
785
786 nsAutoString tagName;
787 if (uriEnd && nameEnd) {
788 // We have a prefix.
789 tagName.Append(nameEnd + 1, pos - nameEnd - 1);
790 tagName.Append(char16_t(':'));
791 }
792 const char16_t* nameStart = uriEnd ? uriEnd + 1 : mismatch;
793 tagName.Append(nameStart, (nameEnd ? nameEnd : pos) - nameStart);
794
795 nsAutoString msg;
796 nsParserMsgUtils::GetLocalizedStringByName(
797 spoofEnglish ? XMLPARSER_PROPERTIES_en_US : XMLPARSER_PROPERTIES,
798 "Expected", msg);
799
800 // . Expected: </%S>.
801 nsAutoString message;
802 nsTextFormatter::ssprintf(message, msg.get(), tagName.get());
803 description.Append(message);
804 }
805
806 // Adjust the column number so that it is one based rather than zero based.
807 uint32_t colNumber = XML_GetCurrentColumnNumber(mExpatParser) + 1;
808 uint32_t lineNumber = XML_GetCurrentLineNumber(mExpatParser);
809
810 nsAutoString errorText;
811 CreateErrorText(description.get(), XML_GetBase(mExpatParser), lineNumber,
812 colNumber, errorText, spoofEnglish);
813
814 nsAutoString sourceText(mLastLine);
815 AppendErrorPointer(colNumber, mLastLine.get(), sourceText);
816
817 // Try to create and initialize the script error.
818 nsCOMPtr<nsIScriptError> serr(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
819 nsresult rv = NS_ERROR_FAILURE;
820 if (serr) {
821 rv = serr->InitWithWindowID(errorText, mURISpec, mLastLine, lineNumber,
822 colNumber, nsIScriptError::errorFlag,
823 "malformed-xml", mInnerWindowID);
824 }
825
826 // If it didn't initialize, we can't do any logging.
827 bool shouldReportError = NS_SUCCEEDED(rv);
828
829 // mSink might be null here if our parser was terminated.
830 if (mSink && shouldReportError) {
831 rv = mSink->ReportError(errorText.get(), sourceText.get(), serr,
832 &shouldReportError);
833 if (NS_FAILED(rv)) {
834 shouldReportError = true;
835 }
836 }
837
838 // mOriginalSink might be null here if our parser was terminated.
839 if (mOriginalSink) {
840 nsCOMPtr<Document> doc = do_QueryInterface(mOriginalSink->GetTarget());
841 if (doc && doc->SuppressParserErrorConsoleMessages()) {
842 shouldReportError = false;
843 }
844 }
845
846 if (shouldReportError) {
847 nsCOMPtr<nsIConsoleService> cs(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
848 if (cs) {
849 cs->LogMessage(serr);
850 }
851 }
852
853 return NS_ERROR_HTMLPARSER_STOPPARSING;
854 }
855
ParseBuffer(const char16_t * aBuffer,uint32_t aLength,bool aIsFinal,uint32_t * aConsumed)856 void nsExpatDriver::ParseBuffer(const char16_t* aBuffer, uint32_t aLength,
857 bool aIsFinal, uint32_t* aConsumed) {
858 NS_ASSERTION((aBuffer && aLength != 0) || (!aBuffer && aLength == 0), "?");
859 NS_ASSERTION(mInternalState != NS_OK || aIsFinal || aBuffer,
860 "Useless call, we won't call Expat");
861 MOZ_ASSERT(!BlockedOrInterrupted() || !aBuffer,
862 "Non-null buffer when resuming");
863 MOZ_ASSERT(XML_GetCurrentByteIndex(mExpatParser) % sizeof(char16_t) == 0,
864 "Consumed part of a char16_t?");
865
866 if (mExpatParser && (mInternalState == NS_OK || BlockedOrInterrupted())) {
867 int32_t parserBytesBefore = XML_GetCurrentByteIndex(mExpatParser);
868 NS_ASSERTION(parserBytesBefore >= 0, "Unexpected value");
869
870 XML_Status status;
871 if (BlockedOrInterrupted()) {
872 mInternalState = NS_OK; // Resume in case we're blocked.
873 status = XML_ResumeParser(mExpatParser);
874 } else {
875 status = XML_Parse(mExpatParser, reinterpret_cast<const char*>(aBuffer),
876 aLength * sizeof(char16_t), aIsFinal);
877 }
878
879 int32_t parserBytesConsumed = XML_GetCurrentByteIndex(mExpatParser);
880
881 NS_ASSERTION(parserBytesConsumed >= 0, "Unexpected value");
882 NS_ASSERTION(parserBytesConsumed >= parserBytesBefore,
883 "How'd this happen?");
884 NS_ASSERTION(parserBytesConsumed % sizeof(char16_t) == 0,
885 "Consumed part of a char16_t?");
886
887 // Consumed something.
888 *aConsumed = (parserBytesConsumed - parserBytesBefore) / sizeof(char16_t);
889 NS_ASSERTION(*aConsumed <= aLength + mExpatBuffered,
890 "Too many bytes consumed?");
891
892 NS_ASSERTION(status != XML_STATUS_SUSPENDED || BlockedOrInterrupted(),
893 "Inconsistent expat suspension state.");
894
895 if (status == XML_STATUS_ERROR) {
896 mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
897 }
898 } else {
899 *aConsumed = 0;
900 }
901 }
902
903 NS_IMETHODIMP
ConsumeToken(nsScanner & aScanner,bool & aFlushTokens)904 nsExpatDriver::ConsumeToken(nsScanner& aScanner, bool& aFlushTokens) {
905 // We keep the scanner pointing to the position where Expat will start
906 // parsing.
907 nsScannerIterator currentExpatPosition;
908 aScanner.CurrentPosition(currentExpatPosition);
909
910 // This is the start of the first buffer that we need to pass to Expat.
911 nsScannerIterator start = currentExpatPosition;
912 start.advance(mExpatBuffered);
913
914 // This is the end of the last buffer (at this point, more data could come in
915 // later).
916 nsScannerIterator end;
917 aScanner.EndReading(end);
918
919 MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
920 ("Remaining in expat's buffer: %i, remaining in scanner: %zu.",
921 mExpatBuffered, Distance(start, end)));
922
923 // We want to call Expat if we have more buffers, or if we know there won't
924 // be more buffers (and so we want to flush the remaining data), or if we're
925 // currently blocked and there's data in Expat's buffer.
926 while (start != end || (mIsFinalChunk && !mMadeFinalCallToExpat) ||
927 (BlockedOrInterrupted() && mExpatBuffered > 0)) {
928 bool noMoreBuffers = start == end && mIsFinalChunk;
929 bool blocked = BlockedOrInterrupted();
930
931 const char16_t* buffer;
932 uint32_t length;
933 if (blocked || noMoreBuffers) {
934 // If we're blocked we just resume Expat so we don't need a buffer, if
935 // there aren't any more buffers we pass a null buffer to Expat.
936 buffer = nullptr;
937 length = 0;
938
939 if (blocked) {
940 MOZ_LOG(
941 gExpatDriverLog, LogLevel::Debug,
942 ("Resuming Expat, will parse data remaining in Expat's "
943 "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n",
944 NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered)
945 .get()));
946 } else {
947 NS_ASSERTION(mExpatBuffered == Distance(currentExpatPosition, end),
948 "Didn't pass all the data to Expat?");
949 MOZ_LOG(
950 gExpatDriverLog, LogLevel::Debug,
951 ("Last call to Expat, will parse data remaining in Expat's "
952 "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n",
953 NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered)
954 .get()));
955 }
956 } else {
957 buffer = start.get();
958 length = uint32_t(start.size_forward());
959
960 MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
961 ("Calling Expat, will parse data remaining in Expat's buffer and "
962 "new data.\nContent of Expat's buffer:\n-----\n%s\n-----\nNew "
963 "data:\n-----\n%s\n-----\n",
964 NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered)
965 .get(),
966 NS_ConvertUTF16toUTF8(start.get(), length).get()));
967 }
968
969 uint32_t consumed;
970 ParseBuffer(buffer, length, noMoreBuffers, &consumed);
971 if (consumed > 0) {
972 nsScannerIterator oldExpatPosition = currentExpatPosition;
973 currentExpatPosition.advance(consumed);
974
975 // We consumed some data, we want to store the last line of data that
976 // was consumed in case we run into an error (to show the line in which
977 // the error occurred).
978
979 // The length of the last line that Expat has parsed.
980 XML_Size lastLineLength = XML_GetCurrentColumnNumber(mExpatParser);
981
982 if (lastLineLength <= consumed) {
983 // The length of the last line was less than what expat consumed, so
984 // there was at least one line break in the consumed data. Store the
985 // last line until the point where we stopped parsing.
986 nsScannerIterator startLastLine = currentExpatPosition;
987 startLastLine.advance(-((ptrdiff_t)lastLineLength));
988 if (!CopyUnicodeTo(startLastLine, currentExpatPosition, mLastLine)) {
989 return (mInternalState = NS_ERROR_OUT_OF_MEMORY);
990 }
991 } else {
992 // There was no line break in the consumed data, append the consumed
993 // data.
994 if (!AppendUnicodeTo(oldExpatPosition, currentExpatPosition,
995 mLastLine)) {
996 return (mInternalState = NS_ERROR_OUT_OF_MEMORY);
997 }
998 }
999 }
1000
1001 mExpatBuffered += length - consumed;
1002
1003 if (BlockedOrInterrupted()) {
1004 MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
1005 ("Blocked or interrupted parser (probably for loading linked "
1006 "stylesheets or scripts)."));
1007
1008 aScanner.SetPosition(currentExpatPosition, true);
1009 aScanner.Mark();
1010
1011 return mInternalState;
1012 }
1013
1014 if (noMoreBuffers && mExpatBuffered == 0) {
1015 mMadeFinalCallToExpat = true;
1016 }
1017
1018 if (NS_FAILED(mInternalState)) {
1019 if (XML_GetErrorCode(mExpatParser) != XML_ERROR_NONE) {
1020 NS_ASSERTION(mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING,
1021 "Unexpected error");
1022
1023 // Look for the next newline after the last one we consumed
1024 nsScannerIterator lastLine = currentExpatPosition;
1025 while (lastLine != end) {
1026 length = uint32_t(lastLine.size_forward());
1027 uint32_t endOffset = 0;
1028 const char16_t* buffer = lastLine.get();
1029 while (endOffset < length && buffer[endOffset] != '\n' &&
1030 buffer[endOffset] != '\r') {
1031 ++endOffset;
1032 }
1033 mLastLine.Append(Substring(buffer, buffer + endOffset));
1034 if (endOffset < length) {
1035 // We found a newline.
1036 break;
1037 }
1038
1039 lastLine.advance(length);
1040 }
1041
1042 HandleError();
1043 }
1044
1045 return mInternalState;
1046 }
1047
1048 // Either we have more buffers, or we were blocked (and we'll flush in the
1049 // next iteration), or we should have emptied Expat's buffer.
1050 NS_ASSERTION(!noMoreBuffers || blocked ||
1051 (mExpatBuffered == 0 && currentExpatPosition == end),
1052 "Unreachable data left in Expat's buffer");
1053
1054 start.advance(length);
1055
1056 // It's possible for start to have passed end if we received more data
1057 // (e.g. if we spun the event loop in an inline script). Reload end now
1058 // to compensate.
1059 aScanner.EndReading(end);
1060 }
1061
1062 aScanner.SetPosition(currentExpatPosition, true);
1063 aScanner.Mark();
1064
1065 MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
1066 ("Remaining in expat's buffer: %i, remaining in scanner: %zu.",
1067 mExpatBuffered, Distance(currentExpatPosition, end)));
1068
1069 return NS_SUCCEEDED(mInternalState) ? NS_ERROR_HTMLPARSER_EOF : NS_OK;
1070 }
1071
1072 NS_IMETHODIMP
WillBuildModel(const CParserContext & aParserContext,nsITokenizer * aTokenizer,nsIContentSink * aSink)1073 nsExpatDriver::WillBuildModel(const CParserContext& aParserContext,
1074 nsITokenizer* aTokenizer, nsIContentSink* aSink) {
1075 mSink = do_QueryInterface(aSink);
1076 if (!mSink) {
1077 NS_ERROR("nsExpatDriver didn't get an nsIExpatSink");
1078 // Make sure future calls to us bail out as needed
1079 mInternalState = NS_ERROR_UNEXPECTED;
1080 return mInternalState;
1081 }
1082
1083 mOriginalSink = aSink;
1084
1085 static const XML_Memory_Handling_Suite memsuite = {malloc, realloc, free};
1086
1087 static const char16_t kExpatSeparator[] = {kExpatSeparatorChar, '\0'};
1088
1089 mExpatParser = XML_ParserCreate_MM(kUTF16, &memsuite, kExpatSeparator);
1090 NS_ENSURE_TRUE(mExpatParser, NS_ERROR_FAILURE);
1091
1092 XML_SetReturnNSTriplet(mExpatParser, XML_TRUE);
1093
1094 #ifdef XML_DTD
1095 XML_SetParamEntityParsing(mExpatParser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1096 #endif
1097
1098 mURISpec = aParserContext.mScanner->GetFilename();
1099
1100 XML_SetBase(mExpatParser, mURISpec.get());
1101
1102 nsCOMPtr<Document> doc = do_QueryInterface(mOriginalSink->GetTarget());
1103 if (doc) {
1104 nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
1105 nsCOMPtr<nsPIDOMWindowInner> inner;
1106 if (win) {
1107 inner = win->GetCurrentInnerWindow();
1108 } else {
1109 bool aHasHadScriptHandlingObject;
1110 nsIScriptGlobalObject* global =
1111 doc->GetScriptHandlingObject(aHasHadScriptHandlingObject);
1112 if (global) {
1113 inner = do_QueryInterface(global);
1114 }
1115 }
1116 if (inner) {
1117 mInnerWindowID = inner->WindowID();
1118 }
1119 }
1120
1121 // Set up the callbacks
1122 XML_SetXmlDeclHandler(mExpatParser, Driver_HandleXMLDeclaration);
1123 if (doc && doc->NodePrincipal()->IsSystemPrincipal()) {
1124 XML_SetElementHandler(mExpatParser, HandleStartElementForSystemPrincipal,
1125 HandleEndElementForSystemPrincipal);
1126 } else {
1127 XML_SetElementHandler(mExpatParser, HandleStartElement, HandleEndElement);
1128 }
1129 XML_SetCharacterDataHandler(mExpatParser, Driver_HandleCharacterData);
1130 XML_SetProcessingInstructionHandler(mExpatParser,
1131 Driver_HandleProcessingInstruction);
1132 XML_SetDefaultHandlerExpand(mExpatParser, Driver_HandleDefault);
1133 XML_SetExternalEntityRefHandler(
1134 mExpatParser,
1135 (XML_ExternalEntityRefHandler)Driver_HandleExternalEntityRef);
1136 XML_SetExternalEntityRefHandlerArg(mExpatParser, this);
1137 XML_SetCommentHandler(mExpatParser, Driver_HandleComment);
1138 XML_SetCdataSectionHandler(mExpatParser, Driver_HandleStartCdataSection,
1139 Driver_HandleEndCdataSection);
1140
1141 XML_SetParamEntityParsing(mExpatParser,
1142 XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
1143 XML_SetDoctypeDeclHandler(mExpatParser, Driver_HandleStartDoctypeDecl,
1144 Driver_HandleEndDoctypeDecl);
1145
1146 // Set up the user data.
1147 XML_SetUserData(mExpatParser, this);
1148
1149 return mInternalState;
1150 }
1151
1152 NS_IMETHODIMP
BuildModel(nsITokenizer * aTokenizer,nsIContentSink * aSink)1153 nsExpatDriver::BuildModel(nsITokenizer* aTokenizer, nsIContentSink* aSink) {
1154 return mInternalState;
1155 }
1156
1157 NS_IMETHODIMP
DidBuildModel(nsresult anErrorCode)1158 nsExpatDriver::DidBuildModel(nsresult anErrorCode) {
1159 mOriginalSink = nullptr;
1160 mSink = nullptr;
1161 return NS_OK;
1162 }
1163
1164 NS_IMETHODIMP
WillTokenize(bool aIsFinalChunk)1165 nsExpatDriver::WillTokenize(bool aIsFinalChunk) {
1166 mIsFinalChunk = aIsFinalChunk;
1167 return NS_OK;
1168 }
1169
NS_IMETHODIMP_(void)1170 NS_IMETHODIMP_(void)
1171 nsExpatDriver::Terminate() {
1172 // XXX - not sure what happens to the unparsed data.
1173 if (mExpatParser) {
1174 XML_StopParser(mExpatParser, XML_FALSE);
1175 }
1176 mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
1177 }
1178
NS_IMETHODIMP_(int32_t)1179 NS_IMETHODIMP_(int32_t)
1180 nsExpatDriver::GetType() { return NS_IPARSER_FLAG_XML; }
1181
NS_IMETHODIMP_(nsDTDMode)1182 NS_IMETHODIMP_(nsDTDMode)
1183 nsExpatDriver::GetMode() const { return eDTDMode_full_standards; }
1184
1185 /*************************** Unused methods **********************************/
1186
NS_IMETHODIMP_(bool)1187 NS_IMETHODIMP_(bool)
1188 nsExpatDriver::IsContainer(int32_t aTag) const { return true; }
1189
NS_IMETHODIMP_(bool)1190 NS_IMETHODIMP_(bool)
1191 nsExpatDriver::CanContain(int32_t aParent, int32_t aChild) const {
1192 return true;
1193 }
1194
MaybeStopParser(nsresult aState)1195 void nsExpatDriver::MaybeStopParser(nsresult aState) {
1196 if (NS_FAILED(aState)) {
1197 // If we had a failure we want to override NS_ERROR_HTMLPARSER_INTERRUPTED
1198 // and we want to override NS_ERROR_HTMLPARSER_BLOCK but not with
1199 // NS_ERROR_HTMLPARSER_INTERRUPTED.
1200 if (NS_SUCCEEDED(mInternalState) ||
1201 mInternalState == NS_ERROR_HTMLPARSER_INTERRUPTED ||
1202 (mInternalState == NS_ERROR_HTMLPARSER_BLOCK &&
1203 aState != NS_ERROR_HTMLPARSER_INTERRUPTED)) {
1204 mInternalState = (aState == NS_ERROR_HTMLPARSER_INTERRUPTED ||
1205 aState == NS_ERROR_HTMLPARSER_BLOCK)
1206 ? aState
1207 : NS_ERROR_HTMLPARSER_STOPPARSING;
1208 }
1209
1210 // If we get an error then we need to stop Expat (by calling XML_StopParser
1211 // with false as the last argument). If the parser should be blocked or
1212 // interrupted we need to pause Expat (by calling XML_StopParser with
1213 // true as the last argument).
1214 XML_StopParser(mExpatParser, BlockedOrInterrupted());
1215 } else if (NS_SUCCEEDED(mInternalState)) {
1216 // Only clobber mInternalState with the success code if we didn't block or
1217 // interrupt before.
1218 mInternalState = aState;
1219 }
1220 }
1221