diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 597a57eae0ad..f6bd5720fec0 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1107,7 +1107,7 @@ public: * @param aPrincipal Prinicpal of the document. Must not be null. * @param aScriptObject The object from which the context for event handling * can be got. - * @param aSVGDocument Force SVG Document creation. + * @param aFlavor Select the kind of document to create. * @param aResult [out] The document that was created. */ static nsresult CreateDocument(const nsAString& aNamespaceURI, @@ -1117,7 +1117,7 @@ public: nsIURI* aBaseURI, nsIPrincipal* aPrincipal, nsIScriptGlobalObject* aScriptObject, - bool aSVGDocument, + DocumentFlavor aFlavor, nsIDOMDocument** aResult); /** diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index a42a92d215cf..9ad61b666197 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -130,6 +130,13 @@ class Element; // Flag for AddStyleSheet(). #define NS_STYLESHEET_FROM_CATALOG (1 << 0) +// Enum for requesting a particular type of document when creating a doc +enum DocumentFlavor { + DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant + DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true + DocumentFlavorSVG // SVGDocument +}; + // Document states // RTL locale: specific to the XUL localedir attribute @@ -1891,7 +1898,7 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult, nsIPrincipal* aPrincipal, bool aLoadedAsData, nsIScriptGlobalObject* aEventObject, - bool aSVGDocument); + DocumentFlavor aFlavor); // This is used only for xbl documents created from the startup cache. // Non-cached documents are created in the same manner as xml documents. diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index f6c6bcd3510f..e938a572c3bc 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -3706,12 +3706,12 @@ nsContentUtils::CreateDocument(const nsAString& aNamespaceURI, nsIURI* aDocumentURI, nsIURI* aBaseURI, nsIPrincipal* aPrincipal, nsIScriptGlobalObject* aEventObject, - bool aSVGDocument, + DocumentFlavor aFlavor, nsIDOMDocument** aResult) { nsresult rv = NS_NewDOMDocument(aResult, aNamespaceURI, aQualifiedName, aDoctype, aDocumentURI, aBaseURI, aPrincipal, - true, aEventObject, aSVGDocument); + true, aEventObject, aFlavor); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr document = do_QueryInterface(*aResult); diff --git a/content/base/src/nsDOMParser.cpp b/content/base/src/nsDOMParser.cpp index c97a65eaf6a8..0cda52149ee0 100644 --- a/content/base/src/nsDOMParser.cpp +++ b/content/base/src/nsDOMParser.cpp @@ -188,7 +188,9 @@ nsDOMParser::ParseFromStream(nsIInputStream *stream, rv = nsContentUtils::CreateDocument(EmptyString(), EmptyString(), nsnull, mDocumentURI, mBaseURI, mOriginalPrincipal, - scriptHandlingObject, svg, + scriptHandlingObject, + svg ? DocumentFlavorSVG : + DocumentFlavorLegacyGuess, getter_AddRefs(domDocument)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 8915d789ec7d..0d0fd22e62d3 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1447,7 +1447,9 @@ nsDOMImplementation::CreateDocument(const nsAString& aNamespaceURI, return nsContentUtils::CreateDocument(aNamespaceURI, aQualifiedName, aDoctype, mDocumentURI, mBaseURI, mOwner->NodePrincipal(), - scriptHandlingObject, false, aReturn); + scriptHandlingObject, + DocumentFlavorLegacyGuess, + aReturn); } NS_IMETHODIMP @@ -1479,7 +1481,8 @@ nsDOMImplementation::CreateHTMLDocument(const nsAString& aTitle, rv = nsContentUtils::CreateDocument(EmptyString(), EmptyString(), doctype, mDocumentURI, mBaseURI, mOwner->NodePrincipal(), - scriptHandlingObject, false, + scriptHandlingObject, + DocumentFlavorLegacyGuess, getter_AddRefs(document)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr doc = do_QueryInterface(document); diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 570ef6bcbb74..bc6817b74001 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -70,7 +70,6 @@ #include "nsCExternalHandlerService.h" #include "nsIVariant.h" #include "xpcprivate.h" -#include "nsIParser.h" #include "nsStringStream.h" #include "nsIStreamConverterService.h" #include "nsICachingChannel.h" @@ -154,6 +153,8 @@ using namespace mozilla; #define NS_PROGRESS_EVENT_INTERVAL 50 +NS_IMPL_ISUPPORTS1(nsXHRParseEndListener, nsIDOMEventListener) + class nsResumeTimeoutsEvent : public nsRunnable { public: @@ -429,7 +430,10 @@ nsXMLHttpRequest::nsXMLHttpRequest() mUploadProgress(0), mUploadProgressMax(0), mErrorLoad(false), mTimerIsActive(false), mProgressEventWasDelayed(false), - mLoadLengthComputable(false), mLoadTotal(0), + mLoadLengthComputable(false), + mIsHtml(false), + mWarnAboutMultipartHtml(false), + mLoadTotal(0), mFirstStartRequestSeen(false), mInLoadProgressEvent(false), mResultJSON(JSVAL_VOID), @@ -719,7 +723,20 @@ nsXMLHttpRequest::GetResponseXML(nsIDOMDocument **aResponseXML) *aResponseXML = mResponseXML; NS_ADDREF(*aResponseXML); } - + if (mWarnAboutMultipartHtml) { + mWarnAboutMultipartHtml = false; + nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES, + "HTMLMultipartXHRWarning", + nsnull, + 0, + nsnull, // Response URL not kept around + EmptyString(), + 0, + 0, + nsIScriptError::warningFlag, + "DOM Events", + mOwner->WindowID()); + } return NS_OK; } @@ -850,7 +867,7 @@ NS_IMETHODIMP nsXMLHttpRequest::GetResponseText(nsAString& aResponseText) // We only decode text lazily if we're also parsing to a doc. // Also, if we've decoded all current data already, then no need to decode // more. - if (!mResponseXML || + if (IsWaitingForHTMLCharset() || !mResponseXML || mResponseBodyDecodedPos == mResponseBody.Length()) { aResponseText = mResponseText; return NS_OK; @@ -1446,6 +1463,16 @@ nsXMLHttpRequest::IsSystemXHR() return !!nsContentUtils::IsSystemPrincipal(mPrincipal); } +bool +nsXMLHttpRequest::IsWaitingForHTMLCharset() +{ + if (!mIsHtml) { + return false; + } + nsCOMPtr doc = do_QueryInterface(mResponseXML); + return doc->GetDocumentCharacterSetSource() < kCharsetFromDocTypeDefault; +} + nsresult nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel) { @@ -1878,6 +1905,8 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt) parseBody = !method.EqualsLiteral("HEAD"); } + mIsHtml = false; + mWarnAboutMultipartHtml = false; if (parseBody && NS_SUCCEEDED(status)) { // We can gain a huge performance win by not even trying to // parse non-XML data. This also protects us from the situation @@ -1886,7 +1915,25 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt) nsCAutoString type; channel->GetContentType(type); - if (type.Find("xml") == kNotFound) { + if (type.EqualsLiteral("text/html")) { + if (mState & XML_HTTP_REQUEST_MULTIPART) { + // HTML parsing is supported only for non-multipart responses. The + // multipart implementation assumes that it's OK to start the next part + // immediately after the last part. That doesn't work with the HTML + // parser, because when OnStopRequest for one part has fired, the + // parser thread still hasn't posted back the runnables that make the + // parsing appear finished. + // + // On the other hand, multipart support seems to be a legacy feature, + // so it isn't clear that use cases justify adding support for deferring + // the multipart stream events between parts to accommodate the + // asynchronous nature of the HTML parser. + mWarnAboutMultipartHtml = true; + mState &= ~XML_HTTP_REQUEST_PARSEBODY; + } else { + mIsHtml = true; + } + } else if (type.Find("xml") == kNotFound) { mState &= ~XML_HTTP_REQUEST_PARSEBODY; } } else { @@ -1911,7 +1958,9 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt) const nsAString& emptyStr = EmptyString(); nsCOMPtr global = do_QueryInterface(mOwner); rv = nsContentUtils::CreateDocument(emptyStr, emptyStr, nsnull, docURI, - baseURI, mPrincipal, global, false, + baseURI, mPrincipal, global, + mIsHtml ? DocumentFlavorHTML : + DocumentFlavorLegacyGuess, getter_AddRefs(mResponseXML)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr responseDoc = do_QueryInterface(mResponseXML); @@ -1996,12 +2045,8 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult return NS_OK; } - nsCOMPtr parser; - // Is this good enough here? if (mState & XML_HTTP_REQUEST_PARSEBODY && mXMLParserStreamListener) { - parser = do_QueryInterface(mXMLParserStreamListener); - NS_ABORT_IF_FALSE(parser, "stream listener was expected to be a parser"); mXMLParserStreamListener->OnStopRequest(request, ctxt, status); } @@ -2010,8 +2055,11 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult mContext = nsnull; // If we're received data since the last progress event, make sure to fire - // an event for it. - MaybeDispatchProgressEvents(true); + // an event for it, except in the HTML case, defer the last progress event + // until the parser is done. + if (!mIsHtml) { + MaybeDispatchProgressEvents(true); + } nsCOMPtr channel(do_QueryInterface(request)); NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED); @@ -2046,8 +2094,6 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult mChannelEventSink = nsnull; mProgressEventSink = nsnull; - mState &= ~XML_HTTP_REQUEST_SYNCLOOPING; - if (NS_FAILED(status)) { // This can happen if the server is unreachable. Other possible // reasons are that the user leaves the page or hits the ESC key. @@ -2056,29 +2102,51 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult mResponseXML = nsnull; } - NS_ASSERTION(!parser || parser->IsParserEnabled(), - "Parser blocked somehow?"); - // If we're uninitialized at this point, we encountered an error // earlier and listeners have already been notified. Also we do // not want to do this if we already completed. if (mState & (XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_DONE)) { + // If we never get far enough to call ChangeStateToDone(), we must be + // careful to stop sync looping. + mState &= ~XML_HTTP_REQUEST_SYNCLOOPING; return NS_OK; } - // We might have been sent non-XML data. If that was the case, - // we should null out the document member. The idea in this - // check here is that if there is no document element it is not - // an XML document. We might need a fancier check... - if (mResponseXML) { - nsCOMPtr root; - mResponseXML->GetDocumentElement(getter_AddRefs(root)); - if (!root) { - mResponseXML = nsnull; + if (mIsHtml) { + nsCOMPtr eventTarget = do_QueryInterface(mResponseXML); + nsEventListenerManager* manager = eventTarget->GetListenerManager(true); + manager->AddEventListenerByType(new nsXHRParseEndListener(this), + NS_LITERAL_STRING("DOMContentLoaded"), + NS_EVENT_FLAG_BUBBLE | + NS_EVENT_FLAG_SYSTEM_EVENT); + } else { + // We might have been sent non-XML data. If that was the case, + // we should null out the document member. The idea in this + // check here is that if there is no document element it is not + // an XML document. We might need a fancier check... + if (!mIsHtml && mResponseXML) { + nsCOMPtr root; + mResponseXML->GetDocumentElement(getter_AddRefs(root)); + if (!root) { + mResponseXML = nsnull; + } } + ChangeStateToDone(); } + return NS_OK; +} + +void +nsXMLHttpRequest::ChangeStateToDone() +{ + mState &= ~XML_HTTP_REQUEST_SYNCLOOPING; + if (mIsHtml) { + // In the HTML case, this has to be deferred, because the parser doesn't + // do it's job synchronously. + MaybeDispatchProgressEvents(true); + } ChangeState(XML_HTTP_REQUEST_DONE, true); NS_NAMED_LITERAL_STRING(errorStr, ERROR_STR); @@ -2104,8 +2172,6 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult // We're a multipart request, so we're not done. Reset to opened. ChangeState(XML_HTTP_REQUEST_OPENED); } - - return NS_OK; } NS_IMETHODIMP @@ -3053,11 +3119,13 @@ nsXMLHttpRequest::MaybeDispatchProgressEvents(bool aFinalProgress) mLoadTotal = mLoadTransferred; mLoadLengthComputable = true; } - mInLoadProgressEvent = true; - DispatchProgressEvent(this, NS_LITERAL_STRING(PROGRESS_STR), - true, mLoadLengthComputable, mLoadTransferred, - mLoadTotal, mLoadTransferred, mLoadTotal); - mInLoadProgressEvent = false; + if (aFinalProgress || !IsWaitingForHTMLCharset()) { + mInLoadProgressEvent = true; + DispatchProgressEvent(this, NS_LITERAL_STRING(PROGRESS_STR), + true, mLoadLengthComputable, mLoadTransferred, + mLoadTotal, mLoadTransferred, mLoadTotal); + mInLoadProgressEvent = false; + } if (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT || mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER) { mResponseBody.Truncate(); diff --git a/content/base/src/nsXMLHttpRequest.h b/content/base/src/nsXMLHttpRequest.h index 9412b03deeca..ad28eaa3668b 100644 --- a/content/base/src/nsXMLHttpRequest.h +++ b/content/base/src/nsXMLHttpRequest.h @@ -123,6 +123,7 @@ class nsXMLHttpRequest : public nsXHREventTarget, public nsIJSNativeInitializer, public nsITimerCallback { + friend class nsXHRParseEndListener; public: nsXMLHttpRequest(); virtual ~nsXMLHttpRequest(); @@ -235,6 +236,10 @@ protected: bool IsSystemXHR(); + bool IsWaitingForHTMLCharset(); + + void ChangeStateToDone(); + /** * Check if aChannel is ok for a cross-site request by making sure no * inappropriate headers are set, and no username/password is set. @@ -347,6 +352,8 @@ protected: bool mTimerIsActive; bool mProgressEventWasDelayed; bool mLoadLengthComputable; + bool mIsHtml; + bool mWarnAboutMultipartHtml; PRUint64 mLoadTotal; // 0 if not known. PRUint64 mLoadTransferred; nsCOMPtr mProgressNotifier; @@ -432,4 +439,24 @@ protected: PRUint64 mMaxProgress; }; +class nsXHRParseEndListener : public nsIDOMEventListener +{ +public: + NS_DECL_ISUPPORTS + NS_IMETHOD HandleEvent(nsIDOMEvent *event) + { + nsCOMPtr xhr = do_QueryReferent(mXHR); + if (xhr) { + static_cast(xhr.get())->ChangeStateToDone(); + } + mXHR = nsnull; + return NS_OK; + } + nsXHRParseEndListener(nsIXMLHttpRequest* aXHR) + : mXHR(do_GetWeakReference(aXHR)) {} + virtual ~nsXHRParseEndListener() {} +private: + nsWeakPtr mXHR; +}; + #endif diff --git a/content/base/test/Makefile.in b/content/base/test/Makefile.in index e9048c7b8b72..abe676dd6f22 100644 --- a/content/base/test/Makefile.in +++ b/content/base/test/Makefile.in @@ -505,6 +505,12 @@ _TEST_FILES2 = \ somedatas.resource \ somedatas.resource^headers^ \ delayedServerEvents.sjs \ + test_html_in_xhr.html \ + file_html_in_xhr.html \ + file_html_in_xhr2.html \ + file_html_in_xhr3.html \ + file_html_in_xhr.sjs \ + file_html_in_xhr_slow.sjs \ test_bug664916.html \ test_bug666604.html \ test_bug675121.html \ diff --git a/content/base/test/file_html_in_xhr.html b/content/base/test/file_html_in_xhr.html new file mode 100644 index 000000000000..d77aeb4402b2 --- /dev/null +++ b/content/base/test/file_html_in_xhr.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/content/base/test/file_html_in_xhr.sjs b/content/base/test/file_html_in_xhr.sjs new file mode 100644 index 000000000000..8f4075ae7cae --- /dev/null +++ b/content/base/test/file_html_in_xhr.sjs @@ -0,0 +1,15 @@ +function handleRequest(request, response) +{ + response.setHeader("Content-Type", "text/javascript", false); + if (request.queryString.indexOf("report") != -1) { + if (getState("loaded") == "loaded") { + response.write("ok(false, 'This script was not supposed to get fetched.'); continueAfterReport();"); + } else { + response.write("ok(true, 'This script was not supposed to get fetched.'); continueAfterReport();"); + } + } else { + setState("loaded", "loaded"); + response.write('document.documentElement.setAttribute("data-fail", "FAIL");'); + } +} + diff --git a/content/base/test/file_html_in_xhr2.html b/content/base/test/file_html_in_xhr2.html new file mode 100644 index 000000000000..046052c753af --- /dev/null +++ b/content/base/test/file_html_in_xhr2.html @@ -0,0 +1 @@ +Þ diff --git a/content/base/test/file_html_in_xhr3.html b/content/base/test/file_html_in_xhr3.html new file mode 100644 index 000000000000..ff43ca409150 --- /dev/null +++ b/content/base/test/file_html_in_xhr3.html @@ -0,0 +1 @@ +SUCCESS diff --git a/content/base/test/file_html_in_xhr_slow.sjs b/content/base/test/file_html_in_xhr_slow.sjs new file mode 100644 index 000000000000..39f47bf72ee3 --- /dev/null +++ b/content/base/test/file_html_in_xhr_slow.sjs @@ -0,0 +1,24 @@ +var timer; + +function handleRequest(request, response) +{ + var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(Components.interfaces.nsIScriptableUnicodeConverter); + converter.charset = "windows-1251"; + var stream = converter.convertToInputStream("\u042E"); + var out = response.bodyOutputStream; + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + out.writeFrom(stream, 1); + var firstPart = ""); + response.finish(); + }, 500, Components.interfaces.nsITimer.TYPE_ONE_SHOT); +} + diff --git a/content/base/test/test_html_in_xhr.html b/content/base/test/test_html_in_xhr.html new file mode 100644 index 000000000000..bae224ea6e50 --- /dev/null +++ b/content/base/test/test_html_in_xhr.html @@ -0,0 +1,118 @@ + + + + + Test for Bug 651072 + + + + + +Mozilla Bug 651072 +

+ +
+
+
+ + + diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 79c8c3b12016..41d7faaf37f6 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -699,7 +699,7 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand, } // TODO: Proper about:blank treatment is bug 543435 - if (loadAsHtml5 && !viewSource) { + if (loadAsHtml5 && aCommand && !nsCRT::strcmp(aCommand, "view")) { // mDocumentURI hasn't been set, yet, so get the URI from the channel nsCOMPtr uri; aChannel->GetOriginalURI(getter_AddRefs(uri)); @@ -771,9 +771,6 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand, // and parentContentViewer nsCOMPtr docShell(do_QueryInterface(aContainer)); - // No support yet for docshell-less HTML - NS_ENSURE_TRUE(docShell || !IsHTML(), NS_ERROR_FAILURE); - nsCOMPtr docShellAsItem(do_QueryInterface(docShell)); nsCOMPtr parentAsItem; @@ -810,9 +807,6 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand, } } - nsCAutoString scheme; - uri->GetScheme(scheme); - nsCAutoString urlSpec; uri->GetSpec(urlSpec); #ifdef DEBUG_charset @@ -830,8 +824,9 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand, nsCOMPtr wyciwygChannel; - if (!IsHTML()) { - charsetSource = kCharsetFromDocTypeDefault; + if (!IsHTML() || !docShell) { // no docshell for text/html XHR + charsetSource = IsHTML() ? kCharsetFromWeakDocTypeDefault + : kCharsetFromDocTypeDefault; charset.AssignLiteral("UTF-8"); TryChannelCharset(aChannel, charsetSource, charset); parserCharsetSource = charsetSource; diff --git a/content/xml/document/src/nsXMLDocument.cpp b/content/xml/document/src/nsXMLDocument.cpp index cbfb8338d6e8..537f5559f2b8 100644 --- a/content/xml/document/src/nsXMLDocument.cpp +++ b/content/xml/document/src/nsXMLDocument.cpp @@ -105,7 +105,7 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult, nsIPrincipal* aPrincipal, bool aLoadedAsData, nsIScriptGlobalObject* aEventObject, - bool aSVGDocument) + DocumentFlavor aFlavor) { // Note: can't require that aDocumentURI/aBaseURI/aPrincipal be non-null, // since at least one caller (XMLHttpRequest) doesn't have decent args to @@ -118,8 +118,11 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult, nsCOMPtr d; bool isHTML = false; bool isXHTML = false; - if (aSVGDocument) { + if (aFlavor == DocumentFlavorSVG) { rv = NS_NewSVGDocument(getter_AddRefs(d)); + } else if (aFlavor == DocumentFlavorHTML) { + rv = NS_NewHTMLDocument(getter_AddRefs(d)); + isHTML = true; } else if (aDoctype) { nsAutoString publicId, name; aDoctype->GetPublicId(publicId); @@ -229,7 +232,7 @@ NS_NewXBLDocument(nsIDOMDocument** aInstancePtrResult, NS_LITERAL_STRING("http://www.mozilla.org/xbl"), NS_LITERAL_STRING("bindings"), nsnull, aDocumentURI, aBaseURI, aPrincipal, false, - nsnull, false); + nsnull, DocumentFlavorLegacyGuess); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr idoc = do_QueryInterface(*aInstancePtrResult); diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index 0da1f443f229..36bf97bdb09c 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -115,3 +115,4 @@ nsIJSONEncodeDeprecatedWarning=nsIJSON.encode is deprecated. Please use JSON.st nsIDOMWindowInternalWarning=Use of nsIDOMWindowInternal is deprecated. Use nsIDOMWindow instead. InputEncodingWarning=Use of inputEncoding is deprecated. GlobalStorageWarning=Use of globalStorage is deprecated. Please use localStorage instead. +HTMLMultipartXHRWarning=HTML parsing in XMLHttpRequest is not supported for multipart responses. \ No newline at end of file diff --git a/parser/html/nsHtml5Parser.cpp b/parser/html/nsHtml5Parser.cpp index 20ce8911ce32..628625e1b0dd 100644 --- a/parser/html/nsHtml5Parser.cpp +++ b/parser/html/nsHtml5Parser.cpp @@ -128,8 +128,10 @@ nsHtml5Parser::GetCommand(nsCString& aCommand) NS_IMETHODIMP_(void) nsHtml5Parser::SetCommand(const char* aCommand) { - NS_ASSERTION(!strcmp(aCommand, "view") || !strcmp(aCommand, "view-source"), - "Parser command was not view"); + NS_ASSERTION(!strcmp(aCommand, "view") || + !strcmp(aCommand, "view-source") || + !strcmp(aCommand, kLoadAsData), + "Unsupported parser command"); } NS_IMETHODIMP_(void) @@ -713,6 +715,8 @@ nsHtml5Parser::MarkAsNotScriptCreated(const char* aCommand) mode = VIEW_SOURCE_XML; } else if (!nsCRT::strcmp(aCommand, "plain-text")) { mode = PLAIN_TEXT; + } else if (!nsCRT::strcmp(aCommand, kLoadAsData)) { + mode = LOAD_AS_DATA; } #ifdef DEBUG else { @@ -830,6 +834,9 @@ nsHtml5Parser::Initialize(nsIDocument* aDoc, void nsHtml5Parser::StartTokenizer(bool aScriptingEnabled) { + if (!aScriptingEnabled) { + mExecutor->PreventScriptExecution(); + } mTreeBuilder->setScriptingEnabled(aScriptingEnabled); mTokenizer->start(); } diff --git a/parser/html/nsHtml5StreamParser.cpp b/parser/html/nsHtml5StreamParser.cpp index d963077a2541..df350dbda2b4 100644 --- a/parser/html/nsHtml5StreamParser.cpp +++ b/parser/html/nsHtml5StreamParser.cpp @@ -356,6 +356,10 @@ void nsHtml5StreamParser::SniffBOMlessUTF16BasicLatin(const PRUint8* aFromSegment, PRUint32 aCountToSniffingLimit) { + // Avoid underspecified heuristic craziness for XHR + if (mMode == LOAD_AS_DATA) { + return; + } // Make sure there's enough data. Require room for "" if (mSniffingLength + aCountToSniffingLimit < 30) { return; @@ -609,6 +613,15 @@ nsHtml5StreamParser::FinalizeSniffing(const PRUint8* aFromSegment, // can be nul mCharset.AssignLiteral("windows-1252"); mCharsetSource = kCharsetFromWeakDocTypeDefault; mTreeBuilder->SetDocumentCharset(mCharset, mCharsetSource); + } else if (mMode == LOAD_AS_DATA && + mCharsetSource == kCharsetFromWeakDocTypeDefault) { + NS_ASSERTION(mReparseForbidden, "Reparse should be forbidden for XHR"); + NS_ASSERTION(!mFeedChardet, "Should not feed chardet for XHR"); + NS_ASSERTION(mCharset.EqualsLiteral("UTF-8"), + "XHR should default to UTF-8"); + // Now mark charset source as non-weak to signal that we have a decision + mCharsetSource = kCharsetFromDocTypeDefault; + mTreeBuilder->SetDocumentCharset(mCharset, mCharsetSource); } return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment, aCount, aWriteCount); } @@ -690,7 +703,9 @@ nsHtml5StreamParser::SniffStreamBytes(const PRUint8* aFromSegment, } // if we get here, there either was no BOM or the BOM sniffing isn't complete yet - if (!mMetaScanner && (mMode == NORMAL || mMode == VIEW_SOURCE_HTML)) { + if (!mMetaScanner && (mMode == NORMAL || + mMode == VIEW_SOURCE_HTML || + mMode == LOAD_AS_DATA)) { mMetaScanner = new nsHtml5MetaScanner(); } @@ -698,7 +713,7 @@ nsHtml5StreamParser::SniffStreamBytes(const PRUint8* aFromSegment, // this is the last buffer PRUint32 countToSniffingLimit = NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE - mSniffingLength; - if (mMode == NORMAL || mMode == VIEW_SOURCE_HTML) { + if (mMode == NORMAL || mMode == VIEW_SOURCE_HTML || mMode == LOAD_AS_DATA) { nsHtml5ByteReadable readable(aFromSegment, aFromSegment + countToSniffingLimit); mMetaScanner->sniff(&readable, getter_AddRefs(mUnicodeDecoder), mCharset); @@ -719,7 +734,7 @@ nsHtml5StreamParser::SniffStreamBytes(const PRUint8* aFromSegment, } // not the last buffer - if (mMode == NORMAL || mMode == VIEW_SOURCE_HTML) { + if (mMode == NORMAL || mMode == VIEW_SOURCE_HTML || mMode == LOAD_AS_DATA) { nsHtml5ByteReadable readable(aFromSegment, aFromSegment + aCount); mMetaScanner->sniff(&readable, getter_AddRefs(mUnicodeDecoder), mCharset); if (mUnicodeDecoder) { @@ -869,7 +884,8 @@ nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) } // For View Source, the parser should run with scripts "enabled" if a normal // load would have scripts enabled. - bool scriptingEnabled = mExecutor->IsScriptEnabled(); + bool scriptingEnabled = mMode == LOAD_AS_DATA ? + false : mExecutor->IsScriptEnabled(); mOwner->StartTokenizer(scriptingEnabled); mTreeBuilder->setScriptingEnabled(scriptingEnabled); mTokenizer->start(); diff --git a/parser/html/nsHtml5StreamParser.h b/parser/html/nsHtml5StreamParser.h index 089818888370..3adbb1d62329 100644 --- a/parser/html/nsHtml5StreamParser.h +++ b/parser/html/nsHtml5StreamParser.h @@ -79,7 +79,12 @@ enum eParserMode { /** * View document as plain text */ - PLAIN_TEXT + PLAIN_TEXT, + + /** + * Load as data (XHR) + */ + LOAD_AS_DATA }; enum eBomState { diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index b85e960deab2..3e2e8f175965 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -737,10 +737,10 @@ nsHtml5TreeOpExecutor::RunScript(nsIContent* aScriptElement) return; } + if (mPreventScriptExecution) { + sele->PreventExecution(); + } if (mFragmentMode) { - if (mPreventScriptExecution) { - sele->PreventExecution(); - } return; } diff --git a/parser/html/nsHtml5TreeOpExecutor.h b/parser/html/nsHtml5TreeOpExecutor.h index d8db889dfafb..c679643edfec 100644 --- a/parser/html/nsHtml5TreeOpExecutor.h +++ b/parser/html/nsHtml5TreeOpExecutor.h @@ -153,7 +153,7 @@ class nsHtml5TreeOpExecutor : public nsContentSink, * */ NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode) { - NS_ASSERTION(GetDocument()->GetScriptGlobalObject(), + NS_ASSERTION(!mDocShell || GetDocument()->GetScriptGlobalObject(), "Script global object not ready"); mDocument->AddObserver(this); WillBuildModelImpl(); @@ -253,6 +253,10 @@ class nsHtml5TreeOpExecutor : public nsContentSink, mPreventScriptExecution = aPreventScriptExecution; } + void PreventScriptExecution() { + mPreventScriptExecution = true; + } + bool IsFragmentMode() { return mFragmentMode; } diff --git a/parser/htmlparser/public/nsIParser.h b/parser/htmlparser/public/nsIParser.h index 4e232b36f29f..02d9d0118b56 100644 --- a/parser/htmlparser/public/nsIParser.h +++ b/parser/htmlparser/public/nsIParser.h @@ -91,7 +91,7 @@ enum eParserDocType { #define kCharsetUninitialized 0 #define kCharsetFromWeakDocTypeDefault 1 #define kCharsetFromUserDefault 2 -#define kCharsetFromDocTypeDefault 3 +#define kCharsetFromDocTypeDefault 3 // This and up confident for XHR #define kCharsetFromCache 4 #define kCharsetFromParentFrame 5 #define kCharsetFromAutoDetection 6