diff --git a/mozilla/content/base/src/nsCrossSiteListenerProxy.cpp b/mozilla/content/base/src/nsCrossSiteListenerProxy.cpp index 99ca24081c9..5ab0cbf764d 100644 --- a/mozilla/content/base/src/nsCrossSiteListenerProxy.cpp +++ b/mozilla/content/base/src/nsCrossSiteListenerProxy.cpp @@ -73,8 +73,12 @@ nsCrossSiteListenerProxy::ForwardRequest(PRBool aFromStop) } mHasForwardedRequest = PR_TRUE; - mParser = nsnull; - mParserListener = nsnull; + + if (mParser) { + mParser->Terminate(); + mParser = nsnull; + mParserListener = nsnull; + } if (mAcceptState != eAccept) { mOuterRequest->Cancel(NS_ERROR_DOM_BAD_URI); @@ -290,8 +294,15 @@ nsCrossSiteListenerProxy::OnDataAvailable(nsIRequest* aRequest, // Hold a local reference to make sure the parser doesn't go away nsCOMPtr stackedListener = mParserListener; - return stackedListener->OnDataAvailable(aRequest, aContext, stream, aOffset, - aCount); + rv = stackedListener->OnDataAvailable(aRequest, aContext, stream, aOffset, + aCount); + // When we forward the request we also terminate the parsing which will + // result in an error bubbling up to here. We want to ignore the error + // in that case. + if (mHasForwardedRequest) { + rv = NS_OK; + } + return rv; } NS_IMETHODIMP @@ -302,7 +313,11 @@ nsCrossSiteListenerProxy::HandleStartElement(const PRUnichar *aName, PRUint32 aLineNumber) { // We're done processing the prolog. - return ForwardRequest(PR_FALSE); + ForwardRequest(PR_FALSE); + + // Block the parser since we don't want to spend more cycles on parsing + // stuff. + return NS_ERROR_HTMLPARSER_BLOCK; } NS_IMETHODIMP @@ -463,7 +478,11 @@ nsCrossSiteListenerProxy::WillBuildModel() mParser->GetDTD(getter_AddRefs(dtd)); NS_ASSERTION(dtd, "missing dtd in WillBuildModel"); if (dtd && !(dtd->GetType() & NS_IPARSER_FLAG_XML)) { - return ForwardRequest(PR_FALSE); + ForwardRequest(PR_FALSE); + + // Block the parser since we don't want to spend more cycles on parsing + // stuff. + return NS_ERROR_HTMLPARSER_BLOCK; } return NS_OK; diff --git a/mozilla/content/base/src/nsXMLHttpRequest.cpp b/mozilla/content/base/src/nsXMLHttpRequest.cpp index 08236bc502b..dcf918970f9 100644 --- a/mozilla/content/base/src/nsXMLHttpRequest.cpp +++ b/mozilla/content/base/src/nsXMLHttpRequest.cpp @@ -87,6 +87,7 @@ #include "nsDOMError.h" #include "nsIHTMLDocument.h" #include "nsWhitespaceTokenizer.h" +#include "nsIMultiPartChannel.h" #define LOAD_STR "load" #define ERROR_STR "error" @@ -116,6 +117,7 @@ #define XML_HTTP_REQUEST_MULTIPART (1 << 12) // Internal #define XML_HTTP_REQUEST_USE_XSITE_AC (1 << 13) // Internal #define XML_HTTP_REQUEST_NON_GET (1 << 14) // Internal +#define XML_HTTP_REQUEST_GOT_FINAL_STOP (1 << 15) // Internal #define XML_HTTP_REQUEST_LOADSTATES \ (XML_HTTP_REQUEST_UNINITIALIZED | \ @@ -1133,6 +1135,12 @@ nsXMLHttpRequest::GetCurrentHttpChannel() static PRBool IsSameOrigin(nsIPrincipal* aPrincipal, nsIChannel* aChannel) { + if (!aPrincipal) { + // XXX Until we got our principal story straight we have to do this to + // support C++ callers. + return PR_TRUE; + } + nsCOMPtr codebase; nsresult rv = aPrincipal->GetURI(getter_AddRefs(codebase)); NS_ENSURE_SUCCESS(rv, rv); @@ -1629,6 +1637,19 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult rv = mXMLParserStreamListener->OnStopRequest(request, ctxt, status); } + nsCOMPtr mpChannel = do_QueryInterface(request); + if (mpChannel) { + PRBool last; + rv = mpChannel->GetIsLastPart(&last); + NS_ENSURE_SUCCESS(rv, rv); + if (last) { + mState |= XML_HTTP_REQUEST_GOT_FINAL_STOP; + } + } + else { + mState |= XML_HTTP_REQUEST_GOT_FINAL_STOP; + } + mXMLParserStreamListener = nsnull; mReadRequest = nsnull; mContext = nsnull; @@ -1719,13 +1740,13 @@ nsXMLHttpRequest::RequestCompleted() // Clear listeners here unless we're multipart ChangeState(XML_HTTP_REQUEST_COMPLETED, PR_TRUE, - !(mState & XML_HTTP_REQUEST_MULTIPART)); + !!(mState & XML_HTTP_REQUEST_GOT_FINAL_STOP)); if (NS_SUCCEEDED(rv) && domevent) { NotifyEventListeners(loadEventListeners, domevent); } - if (mState & XML_HTTP_REQUEST_MULTIPART) { + if (!(mState & XML_HTTP_REQUEST_GOT_FINAL_STOP)) { // We're a multipart request, so we're not done. Reset to opened. ChangeState(XML_HTTP_REQUEST_OPENED); } @@ -1958,13 +1979,6 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) // Create our listener nsCOMPtr listener = this; - if (!(mState & XML_HTTP_REQUEST_XSITEENABLED)) { - // Always create a nsCrossSiteListenerProxy here even if it's - // a same-origin request right now, since it could be redirected. - listener = new nsCrossSiteListenerProxy(listener, mPrincipal); - NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); - } - if (mState & XML_HTTP_REQUEST_MULTIPART) { listener = new nsMultipartProxyListener(listener); if (!listener) { @@ -1972,6 +1986,13 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) } } + if (!(mState & XML_HTTP_REQUEST_XSITEENABLED)) { + // Always create a nsCrossSiteListenerProxy here even if it's + // a same-origin request right now, since it could be redirected. + listener = new nsCrossSiteListenerProxy(listener, mPrincipal); + NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); + } + // Bypass the network cache in cases where it makes no sense: // 1) Multipart responses are very large and would likely be doomed by the // cache once they grow too large, so they are not worth caching. @@ -2009,7 +2030,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) listener = new nsCrossSiteListenerProxy(acListener, mPrincipal); NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); - rv = mACGetChannel->AsyncOpen(acListener, nsnull); + rv = mACGetChannel->AsyncOpen(listener, nsnull); } else { // Start reading from the channel @@ -2066,10 +2087,14 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header, } } - nsCOMPtr httpChannel(do_QueryInterface(mChannel)); - if (!httpChannel) // open() initializes mChannel, and open() + if (!mChannel) // open() initializes mChannel, and open() return NS_ERROR_FAILURE; // must be called before first setRequestHeader() + nsCOMPtr httpChannel(do_QueryInterface(mChannel)); + if (!httpChannel) { + return NS_OK; + } + // Prevent modification to certain HTTP headers (see bug 302263), unless // the executing script has UniversalBrowserWrite permission. diff --git a/mozilla/content/base/src/nsXMLHttpRequest.h b/mozilla/content/base/src/nsXMLHttpRequest.h index 990997c0ee9..523dee47bd7 100644 --- a/mozilla/content/base/src/nsXMLHttpRequest.h +++ b/mozilla/content/base/src/nsXMLHttpRequest.h @@ -168,6 +168,7 @@ protected: nsCOMPtr mContext; nsCOMPtr mPrincipal; nsCOMPtr mChannel; + // mReadRequest is different from mChannel for multipart requests nsCOMPtr mReadRequest; nsCOMPtr mDocument; nsCOMPtr mACGetChannel; diff --git a/mozilla/content/base/test/Makefile.in b/mozilla/content/base/test/Makefile.in index a6626674dfe..a569f0aa914 100644 --- a/mozilla/content/base/test/Makefile.in +++ b/mozilla/content/base/test/Makefile.in @@ -47,6 +47,8 @@ include $(topsrcdir)/config/rules.mk _TEST_FILES = test_bug5141.html \ test_bug51034.html \ test_bug218236.html \ + file_bug218236_multipart.txt \ + file_bug218236_multipart.txt^headers^ \ test_bug218277.html \ test_bug238409.html \ test_bug276037-1.html \ diff --git a/mozilla/content/base/test/file_bug218236_multipart.txt b/mozilla/content/base/test/file_bug218236_multipart.txt new file mode 100644 index 00000000000..ec2962e4e66 --- /dev/null +++ b/mozilla/content/base/test/file_bug218236_multipart.txt @@ -0,0 +1,15 @@ +----boundary +Content-Type: text/html + +File 1 + +------boundary +Content-Type: text/html + +

File 2

+ +------boundary +Content-Type: text/plain + +File 3 +-- diff --git a/mozilla/content/base/test/file_bug218236_multipart.txt^headers^ b/mozilla/content/base/test/file_bug218236_multipart.txt^headers^ new file mode 100644 index 00000000000..8644505d7aa --- /dev/null +++ b/mozilla/content/base/test/file_bug218236_multipart.txt^headers^ @@ -0,0 +1,2 @@ +HTTP 200 OK +Content-Type: multipart/x-mixed-replace;boundary="----boundary" diff --git a/mozilla/content/base/test/test_CrossSiteXHR.html b/mozilla/content/base/test/test_CrossSiteXHR.html index dff6488d5a8..f2b71b7dbe2 100644 --- a/mozilla/content/base/test/test_CrossSiteXHR.html +++ b/mozilla/content/base/test/test_CrossSiteXHR.html @@ -14,30 +14,48 @@
 
 
diff --git a/mozilla/content/base/test/test_bug218236.html b/mozilla/content/base/test/test_bug218236.html index 0e930393028..0dc1cf85e66 100644 --- a/mozilla/content/base/test/test_bug218236.html +++ b/mozilla/content/base/test/test_bug218236.html @@ -27,17 +27,21 @@ SimpleTest.waitForExplicitFinish(); var url_200 = window.location.href; var url_404 = url_200.replace(/[^/]+$/, "this_file_is_not_going_to_be_there.dummy"); var url_connection_error = url_200.replace(/^(\w+:\/\/[^/]+?)(:\d+)?\//, "$1:9546/"); +var url_multipart = "file_bug218236_multipart.txt"; // List of tests: name of the test, URL to be requested, expected sequence // of events and optionally a function to be called from readystatechange handler. // Numbers in the list of events are values of XMLHttpRequest.readyState // when readystatechange event is triggered. var tests = [ - ["200 OK", url_200, [1, 2, 3, 4, "load"], null], - ["404 Not Found", url_404, [1, 2, 3, 4, "load"], null], - ["connection error", url_connection_error, [1, 2, 4, "error"], null], - ["abort() call on readyState = 1", url_200, [1, 4], doAbort1], - ["abort() call on readyState = 2", url_200, [1, 2, 4], doAbort2], + ["200 OK", url_200, [1, 2, 3, 4, "load"], 0, null], + ["404 Not Found", url_404, [1, 2, 3, 4, "load"], 0, null], + ["connection error", url_connection_error, [1, 2, 4, "error"], 0, null], + ["abort() call on readyState = 1", url_200, [1, 4], 0, doAbort1], + ["abort() call on readyState = 2", url_200, [1, 2, 4], 0, doAbort2], + ["multipart document", url_multipart, [1, 2, 3, 4, "load", + 1, 2, 3, 4, "load", + 1, 2, 3, 4, "load"], 1, null], ]; var testName = null; @@ -45,6 +49,7 @@ var currentState = 0; var currentSequence = null; var expectedSequence = null; var currentCallback = null; +var finalizeTimeoutID = null; var request = null; @@ -69,6 +74,7 @@ function runNextTest() { // Prepare request object request = new XMLHttpRequest(); + request.multipart = test[3]; request.open("GET", test[1]); request.onreadystatechange = onReadyStateChange; request.onload = onLoad; @@ -79,7 +85,7 @@ function runNextTest() { currentState = 0; currentSequence = []; expectedSequence = test[2]; - currentCallback = test[3]; + currentCallback = test[4]; // Start request request.send(null); @@ -89,12 +95,16 @@ function runNextTest() { } function finalizeTest() { - ok(compareArrays(expectedSequence, currentSequence), "event sequence for '" + testName + "' should be " + expectedSequence.join(", ")); + finalizeTimeoutID = null; + ok(compareArrays(expectedSequence, currentSequence), "event sequence for '" + testName + "' was " + currentSequence.join(", ")); runNextTest(); } function onReadyStateChange() { + clearTimeout(finalizeTimeoutID); + finalizeTimeoutID = null; + // Ignore duplicated calls for the same ready state if (request.readyState != currentState) { currentState = request.readyState; @@ -103,7 +113,9 @@ function onReadyStateChange() { if (currentState == 4) { // Allow remaining event to fire but then we are finished with this test - setTimeout(finalizeTest, 0); + // unless we get another onReadyStateChange in which case we'll cancel + // this timeout + finalizeTimeoutID = setTimeout(finalizeTest, 0); } if (currentCallback)