mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 732343 - Defend HTML document loading against extensions causing bogus use of the old HTML parser. r=smaug.
This commit is contained in:
parent
11c200ab21
commit
e1c9589023
@ -183,9 +183,10 @@ public:
|
||||
|
||||
/**
|
||||
* Let the document know that we're starting to load data into it.
|
||||
* @param aCommand The parser command
|
||||
* @param aCommand The parser command. Must not be null.
|
||||
* XXXbz It's odd to have that here.
|
||||
* @param aChannel The channel the data will come from
|
||||
* @param aChannel The channel the data will come from. The channel must be
|
||||
* able to report its Content-Type.
|
||||
* @param aLoadGroup The loadgroup this document should use from now on.
|
||||
* Note that the document might not be the only thing using
|
||||
* this loadgroup.
|
||||
@ -204,6 +205,9 @@ public:
|
||||
* @param aSink The content sink to use for the data. If this is null and
|
||||
* the document needs a content sink, it will create one based
|
||||
* on whatever it knows about the data it's going to load.
|
||||
* This MUST be null if the underlying document is an HTML
|
||||
* document. Even in the XML case, please don't add new calls
|
||||
* with non-null sink.
|
||||
*
|
||||
* Once this has been called, the document will return false for
|
||||
* MayStartLayout() until SetMayStartLayout(true) is called on it. Making
|
||||
|
@ -150,8 +150,6 @@ const PRInt32 kBackward = 1;
|
||||
|
||||
//#define DEBUG_charset
|
||||
|
||||
#define NS_USE_NEW_PLAIN_TEXT 1
|
||||
|
||||
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
|
||||
|
||||
PRUint32 nsHTMLDocument::gWyciwygSessionCnt = 0;
|
||||
@ -560,51 +558,56 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
||||
bool aReset,
|
||||
nsIContentSink* aSink)
|
||||
{
|
||||
if (!aCommand) {
|
||||
MOZ_NOT_REACHED("Command is mandatory");
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
if (aSink) {
|
||||
MOZ_NOT_REACHED("Got a sink override. Should not happen for HTML doc.");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
if (!mIsRegularHTML) {
|
||||
MOZ_NOT_REACHED("Must not set HTML doc to XHTML mode before load start.");
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
nsCAutoString contentType;
|
||||
aChannel->GetContentType(contentType);
|
||||
|
||||
bool viewSource = aCommand && !nsCRT::strcmp(aCommand, "view-source");
|
||||
bool plainText = (contentType.EqualsLiteral(TEXT_PLAIN) ||
|
||||
bool view = !strcmp(aCommand, "view") ||
|
||||
!strcmp(aCommand, "external-resource");
|
||||
bool viewSource = !strcmp(aCommand, "view-source");
|
||||
bool asData = !strcmp(aCommand, kLoadAsData);
|
||||
if(!(view || viewSource || asData)) {
|
||||
MOZ_NOT_REACHED("Bad parser command");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
bool html = contentType.EqualsLiteral(TEXT_HTML);
|
||||
bool xhtml = !html && contentType.Equals("application/xhtml+xml");
|
||||
bool plainText = !html && !xhtml && (contentType.EqualsLiteral(TEXT_PLAIN) ||
|
||||
contentType.EqualsLiteral(TEXT_CSS) ||
|
||||
contentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
|
||||
contentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
|
||||
contentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
|
||||
contentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
|
||||
contentType.EqualsLiteral(TEXT_JAVASCRIPT));
|
||||
bool loadAsHtml5 = nsHtml5Module::sEnabled || viewSource || plainText;
|
||||
if (!NS_USE_NEW_PLAIN_TEXT && !viewSource) {
|
||||
plainText = false;
|
||||
if (!(html || xhtml || plainText || viewSource)) {
|
||||
MOZ_NOT_REACHED("Channel with bad content type.");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!(plainText && aSink),
|
||||
"Someone tries to load plain text into a custom sink.");
|
||||
bool loadAsHtml5 = true;
|
||||
|
||||
if (aSink) {
|
||||
loadAsHtml5 = false;
|
||||
}
|
||||
|
||||
if (contentType.Equals("application/xhtml+xml") && !viewSource) {
|
||||
if (!viewSource && xhtml) {
|
||||
// We're parsing XHTML as XML, remember that.
|
||||
|
||||
mIsRegularHTML = false;
|
||||
mCompatMode = eCompatibility_FullStandards;
|
||||
loadAsHtml5 = false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
NS_ASSERTION(mIsRegularHTML,
|
||||
"Hey, someone forgot to reset mIsRegularHTML!!!");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (loadAsHtml5 && !viewSource &&
|
||||
(!(contentType.EqualsLiteral("text/html") || plainText) &&
|
||||
aCommand && !nsCRT::strcmp(aCommand, "view"))) {
|
||||
loadAsHtml5 = false;
|
||||
}
|
||||
|
||||
// TODO: Proper about:blank treatment is bug 543435
|
||||
if (loadAsHtml5 && aCommand && !nsCRT::strcmp(aCommand, "view")) {
|
||||
if (loadAsHtml5 && view) {
|
||||
// mDocumentURI hasn't been set, yet, so get the URI from the channel
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
aChannel->GetOriginalURI(getter_AddRefs(uri));
|
||||
@ -622,14 +625,6 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
||||
|
||||
CSSLoader()->SetCompatibilityMode(mCompatMode);
|
||||
|
||||
bool needsParser = true;
|
||||
if (aCommand)
|
||||
{
|
||||
if (!nsCRT::strcmp(aCommand, "view delayedContentLoad")) {
|
||||
needsParser = false;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = nsDocument::StartDocumentLoad(aCommand,
|
||||
aChannel, aLoadGroup,
|
||||
aContainer,
|
||||
@ -649,7 +644,6 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
||||
|
||||
nsCOMPtr<nsICachingChannel> cachingChan = do_QueryInterface(aChannel);
|
||||
|
||||
if (needsParser) {
|
||||
if (loadAsHtml5) {
|
||||
mParser = nsHtml5Module::NewHtml5Parser();
|
||||
if (plainText) {
|
||||
@ -658,7 +652,7 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
||||
} else {
|
||||
mParser->MarkAsNotScriptCreated("plain-text");
|
||||
}
|
||||
} else if (viewSource && !contentType.EqualsLiteral("text/html")) {
|
||||
} else if (viewSource && !html) {
|
||||
mParser->MarkAsNotScriptCreated("view-source-xml");
|
||||
} else {
|
||||
mParser->MarkAsNotScriptCreated(aCommand);
|
||||
@ -667,7 +661,6 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
||||
mParser = do_CreateInstance(kCParserCID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32 textType = GET_BIDI_OPTION_TEXTTYPE(GetBidiOptions());
|
||||
|
||||
@ -852,7 +845,6 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
||||
}
|
||||
|
||||
// Set the parser as the stream listener for the document loader...
|
||||
if (mParser) {
|
||||
rv = NS_OK;
|
||||
nsCOMPtr<nsIStreamListener> listener = mParser->GetStreamListener();
|
||||
listener.forget(aDocListener);
|
||||
@ -864,42 +856,26 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
||||
mParser->SetDocumentCharset(parserCharset, parserCharsetSource);
|
||||
mParser->SetCommand(aCommand);
|
||||
|
||||
// create the content sink
|
||||
nsCOMPtr<nsIContentSink> sink;
|
||||
|
||||
if (aSink) {
|
||||
NS_ASSERTION(!loadAsHtml5, "Panic: We are loading as HTML5 and someone tries to set an external sink!");
|
||||
sink = aSink;
|
||||
} else {
|
||||
if (!IsHTML()) {
|
||||
MOZ_ASSERT(!loadAsHtml5);
|
||||
nsCOMPtr<nsIXMLContentSink> xmlsink;
|
||||
rv = NS_NewXMLContentSink(getter_AddRefs(xmlsink), this, uri,
|
||||
NS_NewXMLContentSink(getter_AddRefs(xmlsink), this, uri,
|
||||
docShell, aChannel);
|
||||
|
||||
sink = xmlsink;
|
||||
mParser->SetContentSink(xmlsink);
|
||||
} else {
|
||||
if (loadAsHtml5) {
|
||||
nsHtml5Module::Initialize(mParser, this, uri, docShell, aChannel);
|
||||
sink = mParser->GetContentSink();
|
||||
} else {
|
||||
// about:blank *only*
|
||||
nsCOMPtr<nsIHTMLContentSink> htmlsink;
|
||||
|
||||
rv = NS_NewHTMLContentSink(getter_AddRefs(htmlsink), this, uri,
|
||||
NS_NewHTMLContentSink(getter_AddRefs(htmlsink), this, uri,
|
||||
docShell, aChannel);
|
||||
|
||||
sink = htmlsink;
|
||||
mParser->SetContentSink(htmlsink);
|
||||
}
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(sink,
|
||||
"null sink with successful result from factory method");
|
||||
}
|
||||
|
||||
mParser->SetContentSink(sink);
|
||||
// parser the content of the URI
|
||||
mParser->Parse(uri, nsnull, (void *)this);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -1560,35 +1536,13 @@ nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
|
||||
mSecurityInfo = securityInfo;
|
||||
|
||||
mParserAborted = false;
|
||||
bool loadAsHtml5 = nsHtml5Module::sEnabled;
|
||||
if (loadAsHtml5) {
|
||||
mParser = nsHtml5Module::NewHtml5Parser();
|
||||
nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
|
||||
rv = NS_OK;
|
||||
} else {
|
||||
mParser = do_CreateInstance(kCParserCID, &rv);
|
||||
}
|
||||
|
||||
// This will be propagated to the parser when someone actually calls write()
|
||||
SetContentTypeInternal(contentType);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (loadAsHtml5) {
|
||||
nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
|
||||
} else {
|
||||
nsCOMPtr<nsIHTMLContentSink> sink;
|
||||
|
||||
rv = NS_NewHTMLContentSink(getter_AddRefs(sink), this, uri, shell,
|
||||
channel);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Don't use a parser without a content sink.
|
||||
mParser = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
mParser->SetContentSink(sink);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the docshell and the document viewer for the impending
|
||||
// out of band document.write()
|
||||
shell->PrepareForNewContentModel();
|
||||
@ -2271,7 +2225,6 @@ nsHTMLDocument::GenerateParserKey(void)
|
||||
|
||||
// The script loader provides us with the currently executing script element,
|
||||
// which is guaranteed to be unique per script.
|
||||
if (nsHtml5Module::sEnabled) {
|
||||
nsIScriptElement* script = mScriptLoader->GetCurrentParserInsertedScript();
|
||||
if (script && mParser && mParser->IsScriptCreated()) {
|
||||
nsCOMPtr<nsIParser> creatorParser = script->GetCreatorParser();
|
||||
@ -2283,9 +2236,6 @@ nsHTMLDocument::GenerateParserKey(void)
|
||||
}
|
||||
}
|
||||
return script;
|
||||
} else {
|
||||
return mScriptLoader->GetCurrentScript();
|
||||
}
|
||||
}
|
||||
|
||||
/* attribute DOMString designMode; */
|
||||
|
@ -53,7 +53,6 @@
|
||||
using namespace mozilla;
|
||||
|
||||
// static
|
||||
bool nsHtml5Module::sEnabled = true;
|
||||
bool nsHtml5Module::sOffMainThread = true;
|
||||
nsIThread* nsHtml5Module::sStreamParserThread = nsnull;
|
||||
nsIThread* nsHtml5Module::sMainThread = nsnull;
|
||||
|
@ -49,7 +49,6 @@ class nsHtml5Module
|
||||
static already_AddRefed<nsIParser> NewHtml5Parser();
|
||||
static nsresult Initialize(nsIParser* aParser, nsIDocument* aDoc, nsIURI* aURI, nsISupports* aContainer, nsIChannel* aChannel);
|
||||
static nsIThread* GetStreamParserThread();
|
||||
static bool sEnabled;
|
||||
static bool sOffMainThread;
|
||||
private:
|
||||
#ifdef DEBUG
|
||||
|
@ -239,6 +239,7 @@ nsParser::Initialize(bool aConstructor)
|
||||
NS_PARSER_FLAG_CAN_TOKENIZE;
|
||||
|
||||
mProcessingNetworkData = false;
|
||||
mIsAboutBlank = false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -408,6 +409,10 @@ nsParser::SetContentSink(nsIContentSink* aSink)
|
||||
|
||||
if (mSink) {
|
||||
mSink->SetParser(this);
|
||||
nsCOMPtr<nsIHTMLContentSink> htmlSink = do_QueryInterface(mSink);
|
||||
if (htmlSink) {
|
||||
mIsAboutBlank = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1996,6 +2001,18 @@ nsParser::DetectMetaTag(const char* aBytes,
|
||||
return false;
|
||||
}
|
||||
|
||||
static NS_METHOD
|
||||
NoOpParserWriteFunc(nsIInputStream* in,
|
||||
void* closure,
|
||||
const char* fromRawSegment,
|
||||
PRUint32 toOffset,
|
||||
PRUint32 count,
|
||||
PRUint32 *writeCount)
|
||||
{
|
||||
*writeCount = count;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool mNeedCharsetCheck;
|
||||
nsParser* mParser;
|
||||
@ -2088,6 +2105,18 @@ nsParser::OnDataAvailable(nsIRequest *request, nsISupports* aContext,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (mIsAboutBlank) {
|
||||
MOZ_NOT_REACHED("Must not get OnDataAvailable for about:blank");
|
||||
// ... but if an extension tries to feed us data for about:blank in a
|
||||
// release build, silently ignore the data.
|
||||
PRUint32 totalRead;
|
||||
rv = pIStream->ReadSegments(NoOpParserWriteFunc,
|
||||
nsnull,
|
||||
aLength,
|
||||
&totalRead);
|
||||
return rv;
|
||||
}
|
||||
|
||||
CParserContext *theContext = mParserContext;
|
||||
|
||||
while (theContext && theContext->mRequest != request) {
|
||||
|
@ -454,6 +454,7 @@ protected:
|
||||
nsCString mCommandStr;
|
||||
|
||||
bool mProcessingNetworkData;
|
||||
bool mIsAboutBlank;
|
||||
|
||||
static nsICharsetConverterManager* sCharsetConverterManager;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user