diff --git a/dom/xslt/xslt/txExecutionState.cpp b/dom/xslt/xslt/txExecutionState.cpp index 9c984e9cd2ad..a3cfddac1c62 100644 --- a/dom/xslt/xslt/txExecutionState.cpp +++ b/dom/xslt/xslt/txExecutionState.cpp @@ -395,7 +395,12 @@ txExecutionState::TemplateRule* txExecutionState::getCurrentTemplateRule() { return &mTemplateRules[mTemplateRules.Length() - 1]; } -txInstruction* txExecutionState::getNextInstruction() { +mozilla::Result +txExecutionState::getNextInstruction() { + if (mStopProcessing) { + return mozilla::Err(NS_ERROR_FAILURE); + } + txInstruction* instr = mNextInstruction; if (instr) { mNextInstruction = instr->mNext.get(); diff --git a/dom/xslt/xslt/txExecutionState.h b/dom/xslt/xslt/txExecutionState.h index d8698802335e..7a314cf8a4b8 100644 --- a/dom/xslt/xslt/txExecutionState.h +++ b/dom/xslt/xslt/txExecutionState.h @@ -17,6 +17,7 @@ #include "txStylesheet.h" #include "txXPathTreeWalker.h" #include "nsTArray.h" +#include "mozilla/Result.h" class txAOutputHandlerFactory; class txAXMLEventHandler; @@ -115,13 +116,14 @@ class txExecutionState : public txIMatchContext { } // state-modification functions - txInstruction* getNextInstruction(); + mozilla::Result getNextInstruction(); nsresult runTemplate(txInstruction* aInstruction); nsresult runTemplate(txInstruction* aInstruction, txInstruction* aReturnTo); void gotoInstruction(txInstruction* aNext); void returnFromTemplate(); nsresult bindVariable(const txExpandedName& aName, txAExprResult* aValue); void removeVariable(const txExpandedName& aName); + void stopProcessing() { mStopProcessing = true; } txAXMLEventHandler* mOutputHandler; txAXMLEventHandler* mResultHandler; @@ -156,6 +158,7 @@ class txExecutionState : public txIMatchContext { txKeyHash mKeyHash; RefPtr mRecycler; bool mDisableLoads; + bool mStopProcessing = false; static const int32_t kMaxRecursionDepth; }; diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp index c50a66a40201..6ce9932f8c80 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp @@ -538,6 +538,79 @@ already_AddRefed txMozillaXSLTProcessor::TransformToDocument( return doc.forget(); } +class XSLTProcessRequest final : public nsIRequest { + public: + explicit XSLTProcessRequest(txExecutionState* aState) : mState(aState) {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIREQUEST + + void Done() { mState = nullptr; } + + private: + ~XSLTProcessRequest() {} + txExecutionState* mState; +}; +NS_IMPL_ISUPPORTS(XSLTProcessRequest, nsIRequest) + +NS_IMETHODIMP +XSLTProcessRequest::GetName(nsACString& aResult) { + aResult.AssignLiteral("about:xslt-load-blocker"); + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::IsPending(bool* _retval) { + *_retval = true; + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::GetStatus(nsresult* status) { + *status = NS_OK; + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::Cancel(nsresult status) { + mState->stopProcessing(); + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::Suspend(void) { return NS_OK; } + +NS_IMETHODIMP +XSLTProcessRequest::Resume(void) { return NS_OK; } + +NS_IMETHODIMP +XSLTProcessRequest::GetLoadGroup(nsILoadGroup** aLoadGroup) { + *aLoadGroup = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::SetLoadGroup(nsILoadGroup* aLoadGroup) { return NS_OK; } + +NS_IMETHODIMP +XSLTProcessRequest::GetLoadFlags(nsLoadFlags* aLoadFlags) { + *aLoadFlags = nsIRequest::LOAD_NORMAL; + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::SetLoadFlags(nsLoadFlags aLoadFlags) { return NS_OK; } + +NS_IMETHODIMP +XSLTProcessRequest::GetTRRMode(nsIRequest::TRRMode* aTRRMode) { + return GetTRRModeImpl(aTRRMode); +} + +NS_IMETHODIMP +XSLTProcessRequest::SetTRRMode(nsIRequest::TRRMode aTRRMode) { + return SetTRRModeImpl(aTRRMode); +} + nsresult txMozillaXSLTProcessor::TransformToDoc(Document** aResult, bool aCreateDataDocument) { UniquePtr sourceNode( @@ -548,10 +621,29 @@ nsresult txMozillaXSLTProcessor::TransformToDoc(Document** aResult, txExecutionState es(mStylesheet, IsLoadDisabled()); + Document* sourceDoc = mSource->OwnerDoc(); + nsCOMPtr loadGroup = sourceDoc->GetDocumentLoadGroup(); + if (!loadGroup) { + nsCOMPtr win = do_QueryInterface(mOwner); + if (win && win->IsCurrentInnerWindow()) { + Document* doc = win->GetDoc(); + if (doc) { + loadGroup = doc->GetDocumentLoadGroup(); + } + } + + if (!loadGroup) { + return NS_ERROR_FAILURE; + } + } + + RefPtr xsltProcessRequest = new XSLTProcessRequest(&es); + loadGroup->AddRequest(xsltProcessRequest, nullptr); + // XXX Need to add error observers // If aResult is non-null, we're a data document - txToDocHandlerFactory handlerFactory(&es, mSource->OwnerDoc(), mObserver, + txToDocHandlerFactory handlerFactory(&es, sourceDoc, mObserver, aCreateDataDocument); es.mOutputHandlerFactory = &handlerFactory; @@ -562,6 +654,9 @@ nsresult txMozillaXSLTProcessor::TransformToDoc(Document** aResult, rv = txXSLTProcessor::execute(es); } + xsltProcessRequest->Done(); + loadGroup->RemoveRequest(xsltProcessRequest, nullptr, NS_OK); + nsresult endRv = es.end(rv); if (NS_SUCCEEDED(rv)) { rv = endRv; diff --git a/dom/xslt/xslt/txXSLTProcessor.cpp b/dom/xslt/xslt/txXSLTProcessor.cpp index dfcdeb559534..bcf1a611088e 100644 --- a/dom/xslt/xslt/txXSLTProcessor.cpp +++ b/dom/xslt/xslt/txXSLTProcessor.cpp @@ -31,12 +31,20 @@ void txXSLTProcessor::shutdown() { txHandlerTable::shutdown(); } /* static */ nsresult txXSLTProcessor::execute(txExecutionState& aEs) { - nsresult rv = NS_OK; - txInstruction* instr; - while ((instr = aEs.getNextInstruction())) { - rv = instr->execute(aEs); - NS_ENSURE_SUCCESS(rv, rv); - } + nsresult rv; + do { + mozilla::Result result = aEs.getNextInstruction(); + if (result.isErr()) { + return result.unwrapErr(); + } - return NS_OK; + txInstruction* instr = result.unwrap(); + if (!instr) { + return NS_OK; + } + + rv = instr->execute(aEs); + } while (NS_SUCCEEDED(rv)); + + return rv; }