1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is TransforMiiX XSLT processor code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2002
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Peter Van der Beken <peterv@propagandism.org>
24 : * Ryan Jones <sciguyryan@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "nsCOMArray.h"
41 : #include "nsIAuthPrompt.h"
42 : #include "nsCharsetAlias.h"
43 : #include "nsIDOMNode.h"
44 : #include "nsIDOMDocument.h"
45 : #include "nsIDocument.h"
46 : #include "nsIExpatSink.h"
47 : #include "nsIChannelEventSink.h"
48 : #include "nsIInterfaceRequestor.h"
49 : #include "nsILoadGroup.h"
50 : #include "nsINameSpaceManager.h"
51 : #include "nsINodeInfo.h"
52 : #include "nsIParser.h"
53 : #include "nsIRequestObserver.h"
54 : #include "nsIScriptSecurityManager.h"
55 : #include "nsContentPolicyUtils.h"
56 : #include "nsIStreamConverterService.h"
57 : #include "nsSyncLoadService.h"
58 : #include "nsIURI.h"
59 : #include "nsIPrincipal.h"
60 : #include "nsIWindowWatcher.h"
61 : #include "nsIXMLContentSink.h"
62 : #include "nsMimeTypes.h"
63 : #include "nsNetUtil.h"
64 : #include "nsParserCIID.h"
65 : #include "nsGkAtoms.h"
66 : #include "txLog.h"
67 : #include "txMozillaXSLTProcessor.h"
68 : #include "txStylesheetCompiler.h"
69 : #include "txXMLUtils.h"
70 : #include "nsAttrName.h"
71 : #include "nsIScriptError.h"
72 : #include "nsIURL.h"
73 : #include "nsCrossSiteListenerProxy.h"
74 : #include "nsDOMError.h"
75 : #include "mozilla/dom/Element.h"
76 :
77 : using namespace mozilla;
78 :
79 : static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
80 :
81 : static void
82 0 : getSpec(nsIChannel* aChannel, nsAString& aSpec)
83 : {
84 0 : if (!aChannel) {
85 0 : return;
86 : }
87 :
88 0 : nsCOMPtr<nsIURI> uri;
89 0 : aChannel->GetOriginalURI(getter_AddRefs(uri));
90 0 : if (!uri) {
91 : return;
92 : }
93 :
94 0 : nsCAutoString spec;
95 0 : uri->GetSpec(spec);
96 0 : AppendUTF8toUTF16(spec, aSpec);
97 : }
98 :
99 : class txStylesheetSink : public nsIXMLContentSink,
100 : public nsIExpatSink,
101 : public nsIStreamListener,
102 : public nsIInterfaceRequestor
103 0 : {
104 : public:
105 : txStylesheetSink(txStylesheetCompiler* aCompiler, nsIParser* aParser);
106 :
107 : NS_DECL_ISUPPORTS
108 : NS_DECL_NSIEXPATSINK
109 : NS_DECL_NSISTREAMLISTENER
110 : NS_DECL_NSIREQUESTOBSERVER
111 : NS_DECL_NSIINTERFACEREQUESTOR
112 :
113 : // nsIContentSink
114 0 : NS_IMETHOD WillParse(void) { return NS_OK; }
115 : NS_IMETHOD DidBuildModel(bool aTerminated);
116 0 : NS_IMETHOD WillInterrupt(void) { return NS_OK; }
117 0 : NS_IMETHOD WillResume(void) { return NS_OK; }
118 0 : NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
119 0 : virtual void FlushPendingNotifications(mozFlushType aType) { }
120 0 : NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
121 0 : virtual nsISupports *GetTarget() { return nsnull; }
122 :
123 : private:
124 : nsRefPtr<txStylesheetCompiler> mCompiler;
125 : nsCOMPtr<nsIStreamListener> mListener;
126 : bool mCheckedForXML;
127 :
128 : protected:
129 : // This exists solely to suppress a warning from nsDerivedSafe
130 : txStylesheetSink();
131 : };
132 :
133 0 : txStylesheetSink::txStylesheetSink(txStylesheetCompiler* aCompiler,
134 : nsIParser* aParser)
135 : : mCompiler(aCompiler),
136 0 : mCheckedForXML(false)
137 : {
138 0 : mListener = do_QueryInterface(aParser);
139 0 : }
140 :
141 0 : NS_IMPL_ISUPPORTS6(txStylesheetSink,
142 : nsIXMLContentSink,
143 : nsIContentSink,
144 : nsIExpatSink,
145 : nsIStreamListener,
146 : nsIRequestObserver,
147 : nsIInterfaceRequestor)
148 :
149 : NS_IMETHODIMP
150 0 : txStylesheetSink::HandleStartElement(const PRUnichar *aName,
151 : const PRUnichar **aAtts,
152 : PRUint32 aAttsCount,
153 : PRInt32 aIndex,
154 : PRUint32 aLineNumber)
155 : {
156 0 : NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
157 :
158 : nsresult rv =
159 0 : mCompiler->startElement(aName, aAtts, aAttsCount / 2, aIndex);
160 0 : if (NS_FAILED(rv)) {
161 0 : mCompiler->cancel(rv);
162 :
163 0 : return rv;
164 : }
165 :
166 0 : return NS_OK;
167 : }
168 :
169 : NS_IMETHODIMP
170 0 : txStylesheetSink::HandleEndElement(const PRUnichar *aName)
171 : {
172 0 : nsresult rv = mCompiler->endElement();
173 0 : if (NS_FAILED(rv)) {
174 0 : mCompiler->cancel(rv);
175 :
176 0 : return rv;
177 : }
178 :
179 0 : return NS_OK;
180 : }
181 :
182 : NS_IMETHODIMP
183 0 : txStylesheetSink::HandleComment(const PRUnichar *aName)
184 : {
185 0 : return NS_OK;
186 : }
187 :
188 : NS_IMETHODIMP
189 0 : txStylesheetSink::HandleCDataSection(const PRUnichar *aData,
190 : PRUint32 aLength)
191 : {
192 0 : return HandleCharacterData(aData, aLength);
193 : }
194 :
195 : NS_IMETHODIMP
196 0 : txStylesheetSink::HandleDoctypeDecl(const nsAString & aSubset,
197 : const nsAString & aName,
198 : const nsAString & aSystemId,
199 : const nsAString & aPublicId,
200 : nsISupports *aCatalogData)
201 : {
202 0 : return NS_OK;
203 : }
204 :
205 : NS_IMETHODIMP
206 0 : txStylesheetSink::HandleCharacterData(const PRUnichar *aData,
207 : PRUint32 aLength)
208 : {
209 0 : nsresult rv = mCompiler->characters(Substring(aData, aData + aLength));
210 0 : if (NS_FAILED(rv)) {
211 0 : mCompiler->cancel(rv);
212 0 : return rv;
213 : }
214 :
215 0 : return NS_OK;
216 : }
217 :
218 : NS_IMETHODIMP
219 0 : txStylesheetSink::HandleProcessingInstruction(const PRUnichar *aTarget,
220 : const PRUnichar *aData)
221 : {
222 0 : return NS_OK;
223 : }
224 :
225 : NS_IMETHODIMP
226 0 : txStylesheetSink::HandleXMLDeclaration(const PRUnichar *aVersion,
227 : const PRUnichar *aEncoding,
228 : PRInt32 aStandalone)
229 : {
230 0 : return NS_OK;
231 : }
232 :
233 : NS_IMETHODIMP
234 0 : txStylesheetSink::ReportError(const PRUnichar *aErrorText,
235 : const PRUnichar *aSourceText,
236 : nsIScriptError *aError,
237 : bool *_retval)
238 : {
239 0 : NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
240 :
241 : // The expat driver should report the error.
242 0 : *_retval = true;
243 :
244 0 : mCompiler->cancel(NS_ERROR_FAILURE, aErrorText, aSourceText);
245 :
246 0 : return NS_OK;
247 : }
248 :
249 : NS_IMETHODIMP
250 0 : txStylesheetSink::DidBuildModel(bool aTerminated)
251 : {
252 0 : return mCompiler->doneLoading();
253 : }
254 :
255 : NS_IMETHODIMP
256 0 : txStylesheetSink::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
257 : nsIInputStream *aInputStream,
258 : PRUint32 aOffset, PRUint32 aCount)
259 : {
260 0 : if (!mCheckedForXML) {
261 0 : nsCOMPtr<nsIParser> parser = do_QueryInterface(aContext);
262 0 : nsCOMPtr<nsIDTD> dtd;
263 0 : parser->GetDTD(getter_AddRefs(dtd));
264 0 : if (dtd) {
265 0 : mCheckedForXML = true;
266 0 : if (!(dtd->GetType() & NS_IPARSER_FLAG_XML)) {
267 0 : nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
268 0 : nsAutoString spec;
269 0 : getSpec(channel, spec);
270 : mCompiler->cancel(NS_ERROR_XSLT_WRONG_MIME_TYPE, nsnull,
271 0 : spec.get());
272 :
273 0 : return NS_ERROR_XSLT_WRONG_MIME_TYPE;
274 : }
275 : }
276 : }
277 :
278 0 : return mListener->OnDataAvailable(aRequest, aContext, aInputStream,
279 0 : aOffset, aCount);
280 : }
281 :
282 : NS_IMETHODIMP
283 0 : txStylesheetSink::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
284 : {
285 0 : PRInt32 charsetSource = kCharsetFromDocTypeDefault;
286 :
287 0 : nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
288 :
289 : // check channel's charset...
290 0 : nsCAutoString charsetVal;
291 0 : nsCAutoString charset;
292 0 : if (NS_SUCCEEDED(channel->GetContentCharset(charsetVal))) {
293 0 : if (NS_SUCCEEDED(nsCharsetAlias::GetPreferred(charsetVal, charset))) {
294 0 : charsetSource = kCharsetFromChannel;
295 : }
296 : }
297 :
298 0 : if (charset.IsEmpty()) {
299 0 : charset.AssignLiteral("UTF-8");
300 : }
301 :
302 0 : nsCOMPtr<nsIParser> parser = do_QueryInterface(aContext);
303 0 : parser->SetDocumentCharset(charset, charsetSource);
304 :
305 0 : nsCAutoString contentType;
306 0 : channel->GetContentType(contentType);
307 :
308 : // Time to sniff! Note: this should go away once file channels do
309 : // sniffing themselves.
310 0 : nsCOMPtr<nsIURI> uri;
311 0 : channel->GetURI(getter_AddRefs(uri));
312 : bool sniff;
313 0 : if (NS_SUCCEEDED(uri->SchemeIs("file", &sniff)) && sniff &&
314 0 : contentType.Equals(UNKNOWN_CONTENT_TYPE)) {
315 : nsresult rv;
316 : nsCOMPtr<nsIStreamConverterService> serv =
317 0 : do_GetService("@mozilla.org/streamConverters;1", &rv);
318 0 : if (NS_SUCCEEDED(rv)) {
319 0 : nsCOMPtr<nsIStreamListener> converter;
320 0 : rv = serv->AsyncConvertData(UNKNOWN_CONTENT_TYPE,
321 : "*/*",
322 : mListener,
323 : aContext,
324 0 : getter_AddRefs(converter));
325 0 : if (NS_SUCCEEDED(rv)) {
326 0 : mListener = converter;
327 : }
328 : }
329 : }
330 :
331 0 : return mListener->OnStartRequest(aRequest, aContext);
332 : }
333 :
334 : NS_IMETHODIMP
335 0 : txStylesheetSink::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
336 : nsresult aStatusCode)
337 : {
338 0 : bool success = true;
339 :
340 0 : nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
341 0 : if (httpChannel) {
342 0 : httpChannel->GetRequestSucceeded(&success);
343 : }
344 :
345 0 : nsresult result = aStatusCode;
346 0 : if (!success) {
347 : // XXX We sometimes want to use aStatusCode here, but the parser resets
348 : // it to NS_ERROR_NOINTERFACE because we don't implement
349 : // nsIHTMLContentSink.
350 0 : result = NS_ERROR_XSLT_NETWORK_ERROR;
351 : }
352 0 : else if (!mCheckedForXML) {
353 0 : nsCOMPtr<nsIParser> parser = do_QueryInterface(aContext);
354 0 : nsCOMPtr<nsIDTD> dtd;
355 0 : parser->GetDTD(getter_AddRefs(dtd));
356 0 : if (dtd && !(dtd->GetType() & NS_IPARSER_FLAG_XML)) {
357 0 : result = NS_ERROR_XSLT_WRONG_MIME_TYPE;
358 : }
359 : }
360 :
361 0 : if (NS_FAILED(result)) {
362 0 : nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
363 0 : nsAutoString spec;
364 0 : getSpec(channel, spec);
365 0 : mCompiler->cancel(result, nsnull, spec.get());
366 : }
367 :
368 0 : nsresult rv = mListener->OnStopRequest(aRequest, aContext, aStatusCode);
369 0 : mListener = nsnull;
370 0 : return rv;
371 : }
372 :
373 : NS_IMETHODIMP
374 0 : txStylesheetSink::GetInterface(const nsIID& aIID, void** aResult)
375 : {
376 0 : if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
377 0 : NS_ENSURE_ARG(aResult);
378 0 : *aResult = nsnull;
379 :
380 : nsresult rv;
381 : nsCOMPtr<nsIWindowWatcher> wwatcher =
382 0 : do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
383 0 : NS_ENSURE_SUCCESS(rv, rv);
384 :
385 0 : nsCOMPtr<nsIAuthPrompt> prompt;
386 0 : rv = wwatcher->GetNewAuthPrompter(nsnull, getter_AddRefs(prompt));
387 0 : NS_ENSURE_SUCCESS(rv, rv);
388 :
389 0 : nsIAuthPrompt* rawPtr = nsnull;
390 0 : prompt.swap(rawPtr);
391 0 : *aResult = rawPtr;
392 :
393 0 : return NS_OK;
394 : }
395 :
396 0 : return NS_ERROR_NO_INTERFACE;
397 : }
398 :
399 : class txCompileObserver : public txACompileObserver
400 0 : {
401 : public:
402 : txCompileObserver(txMozillaXSLTProcessor* aProcessor,
403 : nsILoadGroup* aLoadGroup);
404 :
405 : TX_DECL_ACOMPILEOBSERVER
406 0 : NS_INLINE_DECL_REFCOUNTING(txCompileObserver)
407 :
408 : nsresult startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
409 : nsIPrincipal* aSourcePrincipal);
410 :
411 : private:
412 : nsRefPtr<txMozillaXSLTProcessor> mProcessor;
413 : nsCOMPtr<nsILoadGroup> mLoadGroup;
414 : nsCOMPtr<nsIPrincipal> mCallerPrincipal;
415 :
416 : protected:
417 : // This exists solely to suppress a warning from nsDerivedSafe
418 : txCompileObserver();
419 : };
420 :
421 0 : txCompileObserver::txCompileObserver(txMozillaXSLTProcessor* aProcessor,
422 : nsILoadGroup* aLoadGroup)
423 : : mProcessor(aProcessor),
424 0 : mLoadGroup(aLoadGroup)
425 : {
426 0 : }
427 :
428 : nsresult
429 0 : txCompileObserver::loadURI(const nsAString& aUri,
430 : const nsAString& aReferrerUri,
431 : txStylesheetCompiler* aCompiler)
432 : {
433 0 : if (mProcessor->IsLoadDisabled()) {
434 0 : return NS_ERROR_XSLT_LOAD_BLOCKED_ERROR;
435 : }
436 :
437 0 : nsCOMPtr<nsIURI> uri;
438 0 : nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri);
439 0 : NS_ENSURE_SUCCESS(rv, rv);
440 :
441 0 : nsCOMPtr<nsIURI> referrerUri;
442 0 : rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri);
443 0 : NS_ENSURE_SUCCESS(rv, rv);
444 :
445 0 : nsCOMPtr<nsIPrincipal> referrerPrincipal;
446 0 : rv = nsContentUtils::GetSecurityManager()->
447 0 : GetCodebasePrincipal(referrerUri, getter_AddRefs(referrerPrincipal));
448 0 : NS_ENSURE_SUCCESS(rv, rv);
449 :
450 : // Content Policy
451 0 : PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
452 : rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET,
453 : uri,
454 : referrerPrincipal,
455 : nsnull,
456 0 : NS_LITERAL_CSTRING("application/xml"),
457 : nsnull,
458 0 : &shouldLoad);
459 0 : NS_ENSURE_SUCCESS(rv, rv);
460 0 : if (NS_CP_REJECTED(shouldLoad)) {
461 0 : return NS_ERROR_DOM_BAD_URI;
462 : }
463 :
464 0 : return startLoad(uri, aCompiler, referrerPrincipal);
465 : }
466 :
467 : void
468 0 : txCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler,
469 : nsresult aResult,
470 : const PRUnichar *aErrorText,
471 : const PRUnichar *aParam)
472 : {
473 0 : if (NS_SUCCEEDED(aResult)) {
474 0 : mProcessor->setStylesheet(aCompiler->getStylesheet());
475 : }
476 : else {
477 0 : mProcessor->reportError(aResult, aErrorText, aParam);
478 : }
479 0 : }
480 :
481 : nsresult
482 0 : txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
483 : nsIPrincipal* aReferrerPrincipal)
484 : {
485 0 : nsCOMPtr<nsIChannel> channel;
486 0 : nsresult rv = NS_NewChannel(getter_AddRefs(channel), aUri);
487 0 : NS_ENSURE_SUCCESS(rv, rv);
488 :
489 0 : channel->SetLoadGroup(mLoadGroup);
490 :
491 0 : channel->SetContentType(NS_LITERAL_CSTRING("text/xml"));
492 :
493 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
494 0 : if (httpChannel) {
495 0 : httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
496 0 : NS_LITERAL_CSTRING("*/*"),
497 0 : false);
498 :
499 0 : nsCOMPtr<nsIURI> referrerURI;
500 0 : aReferrerPrincipal->GetURI(getter_AddRefs(referrerURI));
501 0 : if (referrerURI) {
502 0 : httpChannel->SetReferrer(referrerURI);
503 : }
504 : }
505 :
506 0 : nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID, &rv);
507 0 : NS_ENSURE_SUCCESS(rv, rv);
508 :
509 0 : nsRefPtr<txStylesheetSink> sink = new txStylesheetSink(aCompiler, parser);
510 0 : NS_ENSURE_TRUE(sink, NS_ERROR_OUT_OF_MEMORY);
511 :
512 0 : channel->SetNotificationCallbacks(sink);
513 :
514 0 : parser->SetCommand(kLoadAsData);
515 0 : parser->SetContentSink(sink);
516 0 : parser->Parse(aUri);
517 :
518 : // Always install in case of redirects
519 : nsCOMPtr<nsIStreamListener> listener =
520 : new nsCORSListenerProxy(sink, aReferrerPrincipal, channel,
521 0 : false, &rv);
522 0 : NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
523 0 : NS_ENSURE_SUCCESS(rv, rv);
524 :
525 0 : return channel->AsyncOpen(listener, parser);
526 : }
527 :
528 : nsresult
529 0 : TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor,
530 : nsILoadGroup* aLoadGroup, nsIPrincipal* aCallerPrincipal)
531 : {
532 0 : nsCAutoString spec;
533 0 : aUri->GetSpec(spec);
534 0 : PR_LOG(txLog::xslt, PR_LOG_ALWAYS, ("TX_LoadSheet: %s\n", spec.get()));
535 :
536 : // Content Policy
537 0 : PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
538 : nsresult rv =
539 : NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET,
540 : aUri,
541 : aCallerPrincipal,
542 0 : aProcessor->GetSourceContentModel(),
543 0 : NS_LITERAL_CSTRING("application/xml"),
544 : nsnull,
545 0 : &shouldLoad);
546 0 : NS_ENSURE_SUCCESS(rv, rv);
547 0 : if (NS_CP_REJECTED(shouldLoad)) {
548 0 : return NS_ERROR_DOM_BAD_URI;
549 : }
550 :
551 : nsRefPtr<txCompileObserver> observer =
552 0 : new txCompileObserver(aProcessor, aLoadGroup);
553 0 : NS_ENSURE_TRUE(observer, NS_ERROR_OUT_OF_MEMORY);
554 :
555 : nsRefPtr<txStylesheetCompiler> compiler =
556 0 : new txStylesheetCompiler(NS_ConvertUTF8toUTF16(spec), observer);
557 0 : NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
558 :
559 0 : return observer->startLoad(aUri, compiler, aCallerPrincipal);
560 : }
561 :
562 : /**
563 : * handling DOM->txStylesheet
564 : * Observer needs to do synchronous loads.
565 : */
566 : static nsresult
567 0 : handleNode(nsINode* aNode, txStylesheetCompiler* aCompiler)
568 : {
569 0 : nsresult rv = NS_OK;
570 :
571 0 : if (aNode->IsElement()) {
572 0 : dom::Element* element = aNode->AsElement();
573 :
574 0 : PRUint32 attsCount = element->GetAttrCount();
575 0 : nsAutoArrayPtr<txStylesheetAttr> atts;
576 0 : if (attsCount > 0) {
577 0 : atts = new txStylesheetAttr[attsCount];
578 0 : NS_ENSURE_TRUE(atts, NS_ERROR_OUT_OF_MEMORY);
579 :
580 : PRUint32 counter;
581 0 : for (counter = 0; counter < attsCount; ++counter) {
582 0 : txStylesheetAttr& att = atts[counter];
583 0 : const nsAttrName* name = element->GetAttrNameAt(counter);
584 0 : att.mNamespaceID = name->NamespaceID();
585 0 : att.mLocalName = name->LocalName();
586 0 : att.mPrefix = name->GetPrefix();
587 0 : element->GetAttr(att.mNamespaceID, att.mLocalName, att.mValue);
588 : }
589 : }
590 :
591 0 : nsINodeInfo *ni = element->NodeInfo();
592 :
593 : rv = aCompiler->startElement(ni->NamespaceID(),
594 : ni->NameAtom(),
595 : ni->GetPrefixAtom(), atts,
596 0 : attsCount);
597 0 : NS_ENSURE_SUCCESS(rv, rv);
598 :
599 : // explicitly destroy the attrs here since we no longer need it
600 0 : atts = nsnull;
601 :
602 0 : for (nsIContent* child = element->GetFirstChild();
603 : child;
604 0 : child = child->GetNextSibling()) {
605 :
606 0 : rv = handleNode(child, aCompiler);
607 0 : NS_ENSURE_SUCCESS(rv, rv);
608 : }
609 :
610 0 : rv = aCompiler->endElement();
611 0 : NS_ENSURE_SUCCESS(rv, rv);
612 : }
613 0 : else if (aNode->IsNodeOfType(nsINode::eTEXT)) {
614 0 : nsAutoString chars;
615 0 : static_cast<nsIContent*>(aNode)->AppendTextTo(chars);
616 0 : rv = aCompiler->characters(chars);
617 0 : NS_ENSURE_SUCCESS(rv, rv);
618 : }
619 0 : else if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
620 0 : for (nsIContent* child = aNode->GetFirstChild();
621 : child;
622 0 : child = child->GetNextSibling()) {
623 :
624 0 : rv = handleNode(child, aCompiler);
625 0 : NS_ENSURE_SUCCESS(rv, rv);
626 : }
627 : }
628 :
629 0 : return NS_OK;
630 : }
631 :
632 : class txSyncCompileObserver : public txACompileObserver
633 0 : {
634 : public:
635 : txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor);
636 :
637 : TX_DECL_ACOMPILEOBSERVER
638 0 : NS_INLINE_DECL_REFCOUNTING(txSyncCompileObserver)
639 :
640 : protected:
641 : nsRefPtr<txMozillaXSLTProcessor> mProcessor;
642 : };
643 :
644 0 : txSyncCompileObserver::txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor)
645 0 : : mProcessor(aProcessor)
646 : {
647 0 : }
648 :
649 : nsresult
650 0 : txSyncCompileObserver::loadURI(const nsAString& aUri,
651 : const nsAString& aReferrerUri,
652 : txStylesheetCompiler* aCompiler)
653 : {
654 0 : if (mProcessor->IsLoadDisabled()) {
655 0 : return NS_ERROR_XSLT_LOAD_BLOCKED_ERROR;
656 : }
657 :
658 0 : nsCOMPtr<nsIURI> uri;
659 0 : nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri);
660 0 : NS_ENSURE_SUCCESS(rv, rv);
661 :
662 0 : nsCOMPtr<nsIURI> referrerUri;
663 0 : rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri);
664 0 : NS_ENSURE_SUCCESS(rv, rv);
665 :
666 0 : nsCOMPtr<nsIPrincipal> referrerPrincipal;
667 0 : rv = nsContentUtils::GetSecurityManager()->
668 0 : GetCodebasePrincipal(referrerUri, getter_AddRefs(referrerPrincipal));
669 0 : NS_ENSURE_SUCCESS(rv, rv);
670 :
671 : // Content Policy
672 0 : PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
673 : rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET,
674 : uri,
675 : referrerPrincipal,
676 : nsnull,
677 0 : NS_LITERAL_CSTRING("application/xml"),
678 : nsnull,
679 0 : &shouldLoad);
680 0 : NS_ENSURE_SUCCESS(rv, rv);
681 0 : if (NS_CP_REJECTED(shouldLoad)) {
682 0 : return NS_ERROR_DOM_BAD_URI;
683 : }
684 :
685 : // This is probably called by js, a loadGroup for the channel doesn't
686 : // make sense.
687 0 : nsCOMPtr<nsIDOMDocument> document;
688 : rv = nsSyncLoadService::LoadDocument(uri, referrerPrincipal, nsnull,
689 0 : false, getter_AddRefs(document));
690 0 : NS_ENSURE_SUCCESS(rv, rv);
691 :
692 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);
693 0 : rv = handleNode(doc, aCompiler);
694 0 : if (NS_FAILED(rv)) {
695 0 : nsCAutoString spec;
696 0 : uri->GetSpec(spec);
697 0 : aCompiler->cancel(rv, nsnull, NS_ConvertUTF8toUTF16(spec).get());
698 0 : return rv;
699 : }
700 :
701 0 : rv = aCompiler->doneLoading();
702 0 : return rv;
703 : }
704 :
705 0 : void txSyncCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler,
706 : nsresult aResult,
707 : const PRUnichar *aErrorText,
708 : const PRUnichar *aParam)
709 : {
710 0 : }
711 :
712 : nsresult
713 0 : TX_CompileStylesheet(nsINode* aNode, txMozillaXSLTProcessor* aProcessor,
714 : nsIPrincipal* aCallerPrincipal,
715 : txStylesheet** aStylesheet)
716 : {
717 : // If we move GetBaseURI to nsINode this can be simplified.
718 0 : nsCOMPtr<nsIDocument> doc = aNode->OwnerDoc();
719 :
720 0 : nsCOMPtr<nsIURI> uri;
721 0 : if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
722 0 : uri = static_cast<nsIContent*>(aNode)->GetBaseURI();
723 : }
724 : else {
725 0 : NS_ASSERTION(aNode->IsNodeOfType(nsINode::eDOCUMENT), "not a doc");
726 0 : uri = static_cast<nsIDocument*>(aNode)->GetBaseURI();
727 : }
728 0 : NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
729 :
730 0 : nsCAutoString spec;
731 0 : uri->GetSpec(spec);
732 0 : NS_ConvertUTF8toUTF16 baseURI(spec);
733 :
734 0 : nsIURI* docUri = doc->GetDocumentURI();
735 0 : NS_ENSURE_TRUE(docUri, NS_ERROR_FAILURE);
736 :
737 : // We need to remove the ref, a URI with a ref would mean that we have an
738 : // embedded stylesheet.
739 0 : docUri->CloneIgnoringRef(getter_AddRefs(uri));
740 0 : NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
741 :
742 0 : uri->GetSpec(spec);
743 0 : NS_ConvertUTF8toUTF16 stylesheetURI(spec);
744 :
745 : nsRefPtr<txSyncCompileObserver> obs =
746 0 : new txSyncCompileObserver(aProcessor);
747 0 : NS_ENSURE_TRUE(obs, NS_ERROR_OUT_OF_MEMORY);
748 :
749 : nsRefPtr<txStylesheetCompiler> compiler =
750 0 : new txStylesheetCompiler(stylesheetURI, obs);
751 0 : NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
752 :
753 0 : compiler->setBaseURI(baseURI);
754 :
755 0 : nsresult rv = handleNode(aNode, compiler);
756 0 : if (NS_FAILED(rv)) {
757 0 : compiler->cancel(rv);
758 0 : return rv;
759 : }
760 :
761 0 : rv = compiler->doneLoading();
762 0 : NS_ENSURE_SUCCESS(rv, rv);
763 :
764 0 : *aStylesheet = compiler->getStylesheet();
765 0 : NS_ADDREF(*aStylesheet);
766 :
767 0 : return NS_OK;
768 : }
|