715 lines
21 KiB
C++
715 lines
21 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "nsCOMArray.h"
|
|
#include "nsIAuthPrompt.h"
|
|
#include "nsIDOMNode.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIExpatSink.h"
|
|
#include "nsIChannelEventSink.h"
|
|
#include "nsIInterfaceRequestor.h"
|
|
#include "nsILoadGroup.h"
|
|
#include "nsIParser.h"
|
|
#include "nsCharsetSource.h"
|
|
#include "nsIRequestObserver.h"
|
|
#include "nsIScriptSecurityManager.h"
|
|
#include "nsContentPolicyUtils.h"
|
|
#include "nsIStreamConverterService.h"
|
|
#include "nsSyncLoadService.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIPrincipal.h"
|
|
#include "nsIWindowWatcher.h"
|
|
#include "nsIXMLContentSink.h"
|
|
#include "nsMimeTypes.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsParserCIID.h"
|
|
#include "nsGkAtoms.h"
|
|
#include "txLog.h"
|
|
#include "txMozillaXSLTProcessor.h"
|
|
#include "txStylesheetCompiler.h"
|
|
#include "txXMLUtils.h"
|
|
#include "nsAttrName.h"
|
|
#include "nsIScriptError.h"
|
|
#include "nsIURL.h"
|
|
#include "nsError.h"
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/dom/Element.h"
|
|
#include "mozilla/dom/EncodingUtils.h"
|
|
#include "mozilla/UniquePtr.h"
|
|
|
|
using namespace mozilla;
|
|
using mozilla::dom::EncodingUtils;
|
|
using mozilla::net::ReferrerPolicy;
|
|
|
|
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
|
|
|
|
static void
|
|
getSpec(nsIChannel* aChannel, nsAString& aSpec)
|
|
{
|
|
if (!aChannel) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
aChannel->GetOriginalURI(getter_AddRefs(uri));
|
|
if (!uri) {
|
|
return;
|
|
}
|
|
|
|
nsAutoCString spec;
|
|
uri->GetSpec(spec);
|
|
AppendUTF8toUTF16(spec, aSpec);
|
|
}
|
|
|
|
class txStylesheetSink final : public nsIXMLContentSink,
|
|
public nsIExpatSink,
|
|
public nsIStreamListener,
|
|
public nsIInterfaceRequestor
|
|
{
|
|
public:
|
|
txStylesheetSink(txStylesheetCompiler* aCompiler, nsIParser* aParser);
|
|
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIEXPATSINK
|
|
NS_DECL_NSISTREAMLISTENER
|
|
NS_DECL_NSIREQUESTOBSERVER
|
|
NS_DECL_NSIINTERFACEREQUESTOR
|
|
|
|
// nsIContentSink
|
|
NS_IMETHOD WillParse(void) override { return NS_OK; }
|
|
NS_IMETHOD DidBuildModel(bool aTerminated) override;
|
|
NS_IMETHOD WillInterrupt(void) override { return NS_OK; }
|
|
NS_IMETHOD WillResume(void) override { return NS_OK; }
|
|
NS_IMETHOD SetParser(nsParserBase* aParser) override { return NS_OK; }
|
|
virtual void FlushPendingNotifications(mozFlushType aType) override { }
|
|
NS_IMETHOD SetDocumentCharset(nsACString& aCharset) override { return NS_OK; }
|
|
virtual nsISupports *GetTarget() override { return nullptr; }
|
|
|
|
private:
|
|
RefPtr<txStylesheetCompiler> mCompiler;
|
|
nsCOMPtr<nsIStreamListener> mListener;
|
|
nsCOMPtr<nsIParser> mParser;
|
|
bool mCheckedForXML;
|
|
|
|
protected:
|
|
~txStylesheetSink() {}
|
|
|
|
// This exists solely to suppress a warning from nsDerivedSafe
|
|
txStylesheetSink();
|
|
};
|
|
|
|
txStylesheetSink::txStylesheetSink(txStylesheetCompiler* aCompiler,
|
|
nsIParser* aParser)
|
|
: mCompiler(aCompiler)
|
|
, mParser(aParser)
|
|
, mCheckedForXML(false)
|
|
{
|
|
mListener = do_QueryInterface(aParser);
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(txStylesheetSink,
|
|
nsIXMLContentSink,
|
|
nsIContentSink,
|
|
nsIExpatSink,
|
|
nsIStreamListener,
|
|
nsIRequestObserver,
|
|
nsIInterfaceRequestor)
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::HandleStartElement(const char16_t *aName,
|
|
const char16_t **aAtts,
|
|
uint32_t aAttsCount,
|
|
uint32_t aLineNumber)
|
|
{
|
|
NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
|
|
|
|
nsresult rv =
|
|
mCompiler->startElement(aName, aAtts, aAttsCount / 2);
|
|
if (NS_FAILED(rv)) {
|
|
mCompiler->cancel(rv);
|
|
|
|
return rv;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::HandleEndElement(const char16_t *aName)
|
|
{
|
|
nsresult rv = mCompiler->endElement();
|
|
if (NS_FAILED(rv)) {
|
|
mCompiler->cancel(rv);
|
|
|
|
return rv;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::HandleComment(const char16_t *aName)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::HandleCDataSection(const char16_t *aData,
|
|
uint32_t aLength)
|
|
{
|
|
return HandleCharacterData(aData, aLength);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::HandleDoctypeDecl(const nsAString & aSubset,
|
|
const nsAString & aName,
|
|
const nsAString & aSystemId,
|
|
const nsAString & aPublicId,
|
|
nsISupports *aCatalogData)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::HandleCharacterData(const char16_t *aData,
|
|
uint32_t aLength)
|
|
{
|
|
nsresult rv = mCompiler->characters(Substring(aData, aData + aLength));
|
|
if (NS_FAILED(rv)) {
|
|
mCompiler->cancel(rv);
|
|
return rv;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::HandleProcessingInstruction(const char16_t *aTarget,
|
|
const char16_t *aData)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::HandleXMLDeclaration(const char16_t *aVersion,
|
|
const char16_t *aEncoding,
|
|
int32_t aStandalone)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::ReportError(const char16_t *aErrorText,
|
|
const char16_t *aSourceText,
|
|
nsIScriptError *aError,
|
|
bool *_retval)
|
|
{
|
|
NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
|
|
|
|
// The expat driver should report the error.
|
|
*_retval = true;
|
|
|
|
mCompiler->cancel(NS_ERROR_FAILURE, aErrorText, aSourceText);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::DidBuildModel(bool aTerminated)
|
|
{
|
|
return mCompiler->doneLoading();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
|
|
nsIInputStream *aInputStream,
|
|
uint64_t aOffset, uint32_t aCount)
|
|
{
|
|
if (!mCheckedForXML) {
|
|
nsCOMPtr<nsIDTD> dtd;
|
|
mParser->GetDTD(getter_AddRefs(dtd));
|
|
if (dtd) {
|
|
mCheckedForXML = true;
|
|
if (!(dtd->GetType() & NS_IPARSER_FLAG_XML)) {
|
|
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
|
|
nsAutoString spec;
|
|
getSpec(channel, spec);
|
|
mCompiler->cancel(NS_ERROR_XSLT_WRONG_MIME_TYPE, nullptr,
|
|
spec.get());
|
|
|
|
return NS_ERROR_XSLT_WRONG_MIME_TYPE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return mListener->OnDataAvailable(aRequest, mParser, aInputStream,
|
|
aOffset, aCount);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
|
|
{
|
|
int32_t charsetSource = kCharsetFromDocTypeDefault;
|
|
|
|
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
|
|
|
|
// check channel's charset...
|
|
nsAutoCString charsetVal;
|
|
nsAutoCString charset;
|
|
if (NS_SUCCEEDED(channel->GetContentCharset(charsetVal))) {
|
|
if (EncodingUtils::FindEncodingForLabel(charsetVal, charset)) {
|
|
charsetSource = kCharsetFromChannel;
|
|
}
|
|
}
|
|
|
|
if (charset.IsEmpty()) {
|
|
charset.AssignLiteral("UTF-8");
|
|
}
|
|
|
|
mParser->SetDocumentCharset(charset, charsetSource);
|
|
|
|
nsAutoCString contentType;
|
|
channel->GetContentType(contentType);
|
|
|
|
// Time to sniff! Note: this should go away once file channels do
|
|
// sniffing themselves.
|
|
nsCOMPtr<nsIURI> uri;
|
|
channel->GetURI(getter_AddRefs(uri));
|
|
bool sniff;
|
|
if (NS_SUCCEEDED(uri->SchemeIs("file", &sniff)) && sniff &&
|
|
contentType.Equals(UNKNOWN_CONTENT_TYPE)) {
|
|
nsresult rv;
|
|
nsCOMPtr<nsIStreamConverterService> serv =
|
|
do_GetService("@mozilla.org/streamConverters;1", &rv);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
nsCOMPtr<nsIStreamListener> converter;
|
|
rv = serv->AsyncConvertData(UNKNOWN_CONTENT_TYPE,
|
|
"*/*",
|
|
mListener,
|
|
mParser,
|
|
getter_AddRefs(converter));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
mListener = converter;
|
|
}
|
|
}
|
|
}
|
|
|
|
return mListener->OnStartRequest(aRequest, mParser);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
|
|
nsresult aStatusCode)
|
|
{
|
|
bool success = true;
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
|
|
if (httpChannel) {
|
|
httpChannel->GetRequestSucceeded(&success);
|
|
}
|
|
|
|
nsresult result = aStatusCode;
|
|
if (!success) {
|
|
// XXX We sometimes want to use aStatusCode here, but the parser resets
|
|
// it to NS_ERROR_NOINTERFACE because we don't implement
|
|
// nsIHTMLContentSink.
|
|
result = NS_ERROR_XSLT_NETWORK_ERROR;
|
|
}
|
|
else if (!mCheckedForXML) {
|
|
nsCOMPtr<nsIDTD> dtd;
|
|
mParser->GetDTD(getter_AddRefs(dtd));
|
|
if (dtd && !(dtd->GetType() & NS_IPARSER_FLAG_XML)) {
|
|
result = NS_ERROR_XSLT_WRONG_MIME_TYPE;
|
|
}
|
|
}
|
|
|
|
if (NS_FAILED(result)) {
|
|
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
|
|
nsAutoString spec;
|
|
getSpec(channel, spec);
|
|
mCompiler->cancel(result, nullptr, spec.get());
|
|
}
|
|
|
|
nsresult rv = mListener->OnStopRequest(aRequest, mParser, aStatusCode);
|
|
mListener = nullptr;
|
|
mParser = nullptr;
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
txStylesheetSink::GetInterface(const nsIID& aIID, void** aResult)
|
|
{
|
|
if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
|
|
NS_ENSURE_ARG(aResult);
|
|
*aResult = nullptr;
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIWindowWatcher> wwatcher =
|
|
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIAuthPrompt> prompt;
|
|
rv = wwatcher->GetNewAuthPrompter(nullptr, getter_AddRefs(prompt));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
prompt.forget(aResult);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
return NS_ERROR_NO_INTERFACE;
|
|
}
|
|
|
|
class txCompileObserver final : public txACompileObserver
|
|
{
|
|
public:
|
|
txCompileObserver(txMozillaXSLTProcessor* aProcessor,
|
|
nsIDocument* aLoaderDocument);
|
|
|
|
TX_DECL_ACOMPILEOBSERVER
|
|
NS_INLINE_DECL_REFCOUNTING(txCompileObserver)
|
|
|
|
nsresult startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
|
|
nsIPrincipal* aSourcePrincipal,
|
|
ReferrerPolicy aReferrerPolicy);
|
|
|
|
private:
|
|
RefPtr<txMozillaXSLTProcessor> mProcessor;
|
|
nsCOMPtr<nsIDocument> mLoaderDocument;
|
|
|
|
// This exists solely to suppress a warning from nsDerivedSafe
|
|
txCompileObserver();
|
|
|
|
// Private destructor, to discourage deletion outside of Release():
|
|
~txCompileObserver()
|
|
{
|
|
}
|
|
};
|
|
|
|
txCompileObserver::txCompileObserver(txMozillaXSLTProcessor* aProcessor,
|
|
nsIDocument* aLoaderDocument)
|
|
: mProcessor(aProcessor),
|
|
mLoaderDocument(aLoaderDocument)
|
|
{
|
|
}
|
|
|
|
nsresult
|
|
txCompileObserver::loadURI(const nsAString& aUri,
|
|
const nsAString& aReferrerUri,
|
|
ReferrerPolicy aReferrerPolicy,
|
|
txStylesheetCompiler* aCompiler)
|
|
{
|
|
if (mProcessor->IsLoadDisabled()) {
|
|
return NS_ERROR_XSLT_LOAD_BLOCKED_ERROR;
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIURI> referrerUri;
|
|
rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
PrincipalOriginAttributes attrs;
|
|
nsCOMPtr<nsIPrincipal> referrerPrincipal =
|
|
BasePrincipal::CreateCodebasePrincipal(referrerUri, attrs);
|
|
NS_ENSURE_TRUE(referrerPrincipal, NS_ERROR_FAILURE);
|
|
|
|
return startLoad(uri, aCompiler, referrerPrincipal, aReferrerPolicy);
|
|
}
|
|
|
|
void
|
|
txCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler,
|
|
nsresult aResult,
|
|
const char16_t *aErrorText,
|
|
const char16_t *aParam)
|
|
{
|
|
if (NS_SUCCEEDED(aResult)) {
|
|
mProcessor->setStylesheet(aCompiler->getStylesheet());
|
|
}
|
|
else {
|
|
mProcessor->reportError(aResult, aErrorText, aParam);
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
|
|
nsIPrincipal* aReferrerPrincipal,
|
|
ReferrerPolicy aReferrerPolicy)
|
|
{
|
|
nsCOMPtr<nsILoadGroup> loadGroup = mLoaderDocument->GetDocumentLoadGroup();
|
|
if (!loadGroup) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsCOMPtr<nsIChannel> channel;
|
|
nsresult rv = NS_NewChannelWithTriggeringPrincipal(
|
|
getter_AddRefs(channel),
|
|
aUri,
|
|
mLoaderDocument,
|
|
aReferrerPrincipal, // triggeringPrincipal
|
|
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS,
|
|
nsIContentPolicy::TYPE_XSLT,
|
|
loadGroup);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
channel->SetContentType(NS_LITERAL_CSTRING("text/xml"));
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
|
|
if (httpChannel) {
|
|
nsCOMPtr<nsIURI> referrerURI;
|
|
aReferrerPrincipal->GetURI(getter_AddRefs(referrerURI));
|
|
if (referrerURI) {
|
|
httpChannel->SetReferrerWithPolicy(referrerURI, aReferrerPolicy);
|
|
}
|
|
}
|
|
|
|
nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
RefPtr<txStylesheetSink> sink = new txStylesheetSink(aCompiler, parser);
|
|
NS_ENSURE_TRUE(sink, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
channel->SetNotificationCallbacks(sink);
|
|
|
|
parser->SetCommand(kLoadAsData);
|
|
parser->SetContentSink(sink);
|
|
parser->Parse(aUri);
|
|
|
|
return channel->AsyncOpen2(sink);
|
|
}
|
|
|
|
nsresult
|
|
TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor,
|
|
nsIDocument* aLoaderDocument, ReferrerPolicy aReferrerPolicy)
|
|
{
|
|
nsIPrincipal* principal = aLoaderDocument->NodePrincipal();
|
|
|
|
nsAutoCString spec;
|
|
aUri->GetSpec(spec);
|
|
MOZ_LOG(txLog::xslt, LogLevel::Info, ("TX_LoadSheet: %s\n", spec.get()));
|
|
|
|
RefPtr<txCompileObserver> observer =
|
|
new txCompileObserver(aProcessor, aLoaderDocument);
|
|
NS_ENSURE_TRUE(observer, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
RefPtr<txStylesheetCompiler> compiler =
|
|
new txStylesheetCompiler(NS_ConvertUTF8toUTF16(spec), aReferrerPolicy,
|
|
observer);
|
|
NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return observer->startLoad(aUri, compiler, principal, aReferrerPolicy);
|
|
}
|
|
|
|
/**
|
|
* handling DOM->txStylesheet
|
|
* Observer needs to do synchronous loads.
|
|
*/
|
|
static nsresult
|
|
handleNode(nsINode* aNode, txStylesheetCompiler* aCompiler)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (aNode->IsElement()) {
|
|
dom::Element* element = aNode->AsElement();
|
|
|
|
uint32_t attsCount = element->GetAttrCount();
|
|
UniquePtr<txStylesheetAttr[]> atts;
|
|
if (attsCount > 0) {
|
|
atts = MakeUnique<txStylesheetAttr[]>(attsCount);
|
|
uint32_t counter;
|
|
for (counter = 0; counter < attsCount; ++counter) {
|
|
txStylesheetAttr& att = atts[counter];
|
|
const nsAttrName* name = element->GetAttrNameAt(counter);
|
|
att.mNamespaceID = name->NamespaceID();
|
|
att.mLocalName = name->LocalName();
|
|
att.mPrefix = name->GetPrefix();
|
|
element->GetAttr(att.mNamespaceID, att.mLocalName, att.mValue);
|
|
}
|
|
}
|
|
|
|
mozilla::dom::NodeInfo *ni = element->NodeInfo();
|
|
|
|
rv = aCompiler->startElement(ni->NamespaceID(),
|
|
ni->NameAtom(),
|
|
ni->GetPrefixAtom(), atts.get(),
|
|
attsCount);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// explicitly destroy the attrs here since we no longer need it
|
|
atts = nullptr;
|
|
|
|
for (nsIContent* child = element->GetFirstChild();
|
|
child;
|
|
child = child->GetNextSibling()) {
|
|
|
|
rv = handleNode(child, aCompiler);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
rv = aCompiler->endElement();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
else if (aNode->IsNodeOfType(nsINode::eTEXT)) {
|
|
nsAutoString chars;
|
|
static_cast<nsIContent*>(aNode)->AppendTextTo(chars);
|
|
rv = aCompiler->characters(chars);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
else if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
|
|
for (nsIContent* child = aNode->GetFirstChild();
|
|
child;
|
|
child = child->GetNextSibling()) {
|
|
|
|
rv = handleNode(child, aCompiler);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
class txSyncCompileObserver final : public txACompileObserver
|
|
{
|
|
public:
|
|
explicit txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor);
|
|
|
|
TX_DECL_ACOMPILEOBSERVER
|
|
NS_INLINE_DECL_REFCOUNTING(txSyncCompileObserver)
|
|
|
|
private:
|
|
// Private destructor, to discourage deletion outside of Release():
|
|
~txSyncCompileObserver()
|
|
{
|
|
}
|
|
|
|
RefPtr<txMozillaXSLTProcessor> mProcessor;
|
|
};
|
|
|
|
txSyncCompileObserver::txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor)
|
|
: mProcessor(aProcessor)
|
|
{
|
|
}
|
|
|
|
nsresult
|
|
txSyncCompileObserver::loadURI(const nsAString& aUri,
|
|
const nsAString& aReferrerUri,
|
|
ReferrerPolicy aReferrerPolicy,
|
|
txStylesheetCompiler* aCompiler)
|
|
{
|
|
if (mProcessor->IsLoadDisabled()) {
|
|
return NS_ERROR_XSLT_LOAD_BLOCKED_ERROR;
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIURI> referrerUri;
|
|
rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIPrincipal> referrerPrincipal =
|
|
BasePrincipal::CreateCodebasePrincipal(referrerUri, PrincipalOriginAttributes());
|
|
NS_ENSURE_TRUE(referrerPrincipal, NS_ERROR_FAILURE);
|
|
|
|
// This is probably called by js, a loadGroup for the channel doesn't
|
|
// make sense.
|
|
nsCOMPtr<nsINode> source;
|
|
if (mProcessor) {
|
|
source =
|
|
do_QueryInterface(mProcessor->GetSourceContentModel());
|
|
}
|
|
nsAutoSyncOperation sync(source ? source->OwnerDoc() : nullptr);
|
|
nsCOMPtr<nsIDOMDocument> document;
|
|
|
|
rv = nsSyncLoadService::LoadDocument(uri, nsIContentPolicy::TYPE_XSLT,
|
|
referrerPrincipal,
|
|
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS,
|
|
nullptr, false,
|
|
aReferrerPolicy,
|
|
getter_AddRefs(document));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);
|
|
rv = handleNode(doc, aCompiler);
|
|
if (NS_FAILED(rv)) {
|
|
nsAutoCString spec;
|
|
uri->GetSpec(spec);
|
|
aCompiler->cancel(rv, nullptr, NS_ConvertUTF8toUTF16(spec).get());
|
|
return rv;
|
|
}
|
|
|
|
rv = aCompiler->doneLoading();
|
|
return rv;
|
|
}
|
|
|
|
void txSyncCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler,
|
|
nsresult aResult,
|
|
const char16_t *aErrorText,
|
|
const char16_t *aParam)
|
|
{
|
|
}
|
|
|
|
nsresult
|
|
TX_CompileStylesheet(nsINode* aNode, txMozillaXSLTProcessor* aProcessor,
|
|
txStylesheet** aStylesheet)
|
|
{
|
|
// If we move GetBaseURI to nsINode this can be simplified.
|
|
nsCOMPtr<nsIDocument> doc = aNode->OwnerDoc();
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
|
|
uri = static_cast<nsIContent*>(aNode)->GetBaseURI();
|
|
}
|
|
else {
|
|
NS_ASSERTION(aNode->IsNodeOfType(nsINode::eDOCUMENT), "not a doc");
|
|
uri = static_cast<nsIDocument*>(aNode)->GetBaseURI();
|
|
}
|
|
NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
|
|
|
|
nsAutoCString spec;
|
|
uri->GetSpec(spec);
|
|
NS_ConvertUTF8toUTF16 baseURI(spec);
|
|
|
|
nsIURI* docUri = doc->GetDocumentURI();
|
|
NS_ENSURE_TRUE(docUri, NS_ERROR_FAILURE);
|
|
|
|
// We need to remove the ref, a URI with a ref would mean that we have an
|
|
// embedded stylesheet.
|
|
docUri->CloneIgnoringRef(getter_AddRefs(uri));
|
|
NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
|
|
|
|
uri->GetSpec(spec);
|
|
NS_ConvertUTF8toUTF16 stylesheetURI(spec);
|
|
|
|
RefPtr<txSyncCompileObserver> obs =
|
|
new txSyncCompileObserver(aProcessor);
|
|
NS_ENSURE_TRUE(obs, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
RefPtr<txStylesheetCompiler> compiler =
|
|
new txStylesheetCompiler(stylesheetURI, doc->GetReferrerPolicy(), obs);
|
|
NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
compiler->setBaseURI(baseURI);
|
|
|
|
nsresult rv = handleNode(aNode, compiler);
|
|
if (NS_FAILED(rv)) {
|
|
compiler->cancel(rv);
|
|
return rv;
|
|
}
|
|
|
|
rv = compiler->doneLoading();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
*aStylesheet = compiler->getStylesheet();
|
|
NS_ADDREF(*aStylesheet);
|
|
|
|
return NS_OK;
|
|
}
|