LCOV - code coverage report
Current view: top level - dom/base - DOMParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 211 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 25 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/DOMParser.h"
       8             : 
       9             : #include "nsIDOMDocument.h"
      10             : #include "nsNetUtil.h"
      11             : #include "nsIStreamListener.h"
      12             : #include "nsStringStream.h"
      13             : #include "nsIScriptError.h"
      14             : #include "nsIScriptSecurityManager.h"
      15             : #include "nsCRT.h"
      16             : #include "nsStreamUtils.h"
      17             : #include "nsContentUtils.h"
      18             : #include "nsDOMJSUtils.h"
      19             : #include "nsError.h"
      20             : #include "nsPIDOMWindow.h"
      21             : #include "NullPrincipal.h"
      22             : #include "mozilla/LoadInfo.h"
      23             : #include "mozilla/dom/BindingUtils.h"
      24             : #include "mozilla/dom/ScriptSettings.h"
      25             : 
      26             : using namespace mozilla;
      27             : using namespace mozilla::dom;
      28             : 
      29           0 : DOMParser::DOMParser()
      30             :   : mAttemptedInit(false)
      31           0 :   , mOriginalPrincipalWasSystem(false)
      32             : {
      33           0 : }
      34             : 
      35           0 : DOMParser::~DOMParser()
      36             : {
      37           0 : }
      38             : 
      39             : // QueryInterface implementation for DOMParser
      40           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMParser)
      41           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      42           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMParser)
      43           0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMParser)
      44           0 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
      45           0 : NS_INTERFACE_MAP_END
      46             : 
      47           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMParser, mOwner)
      48             : 
      49           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMParser)
      50           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMParser)
      51             : 
      52             : static const char*
      53           0 : StringFromSupportedType(SupportedType aType)
      54             : {
      55           0 :   return SupportedTypeValues::strings[static_cast<int>(aType)].value;
      56             : }
      57             : 
      58             : already_AddRefed<nsIDocument>
      59           0 : DOMParser::ParseFromString(const nsAString& aStr, SupportedType aType,
      60             :                            ErrorResult& rv)
      61             : {
      62           0 :   nsCOMPtr<nsIDOMDocument> domDocument;
      63           0 :   rv = ParseFromString(aStr,
      64             :                        StringFromSupportedType(aType),
      65           0 :                        getter_AddRefs(domDocument));
      66           0 :   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
      67           0 :   return document.forget();
      68             : }
      69             : 
      70             : NS_IMETHODIMP
      71           0 : DOMParser::ParseFromString(const char16_t *str,
      72             :                            const char *contentType,
      73             :                            nsIDOMDocument **aResult)
      74             : {
      75           0 :   NS_ENSURE_ARG(str);
      76             :   // Converting a string to an enum value manually is a bit of a pain,
      77             :   // so let's just use a helper that takes a content-type string.
      78           0 :   return ParseFromString(nsDependentString(str), contentType, aResult);
      79             : }
      80             : 
      81             : nsresult
      82           0 : DOMParser::ParseFromString(const nsAString& str,
      83             :                            const char *contentType,
      84             :                            nsIDOMDocument **aResult)
      85             : {
      86           0 :   NS_ENSURE_ARG_POINTER(aResult);
      87             : 
      88             :   nsresult rv;
      89             : 
      90           0 :   if (!nsCRT::strcmp(contentType, "text/html")) {
      91           0 :     nsCOMPtr<nsIDOMDocument> domDocument;
      92           0 :     rv = SetUpDocument(DocumentFlavorHTML, getter_AddRefs(domDocument));
      93           0 :     NS_ENSURE_SUCCESS(rv, rv);
      94           0 :     nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
      95             : 
      96             :     // Keep the XULXBL state in sync with the XML case.
      97             : 
      98           0 :     if (mOriginalPrincipalWasSystem) {
      99           0 :       document->ForceEnableXULXBL();
     100             :     }
     101             : 
     102           0 :     rv = nsContentUtils::ParseDocumentHTML(str, document, false);
     103           0 :     NS_ENSURE_SUCCESS(rv, rv);
     104             : 
     105           0 :     domDocument.forget(aResult);
     106           0 :     return rv;
     107             :   }
     108             : 
     109           0 :   nsAutoCString utf8str;
     110             :   // Convert from UTF16 to UTF8 using fallible allocations
     111           0 :   if (!AppendUTF16toUTF8(str, utf8str, mozilla::fallible)) {
     112           0 :     return NS_ERROR_OUT_OF_MEMORY;
     113             :   }
     114             : 
     115             :   // The new stream holds a reference to the buffer
     116           0 :   nsCOMPtr<nsIInputStream> stream;
     117           0 :   rv = NS_NewByteInputStream(getter_AddRefs(stream),
     118           0 :                              utf8str.get(), utf8str.Length(),
     119           0 :                              NS_ASSIGNMENT_DEPEND);
     120           0 :   if (NS_FAILED(rv))
     121           0 :     return rv;
     122             : 
     123           0 :   return ParseFromStream(stream, "UTF-8", utf8str.Length(), contentType, aResult);
     124             : }
     125             : 
     126             : already_AddRefed<nsIDocument>
     127           0 : DOMParser::ParseFromBuffer(const Sequence<uint8_t>& aBuf, uint32_t aBufLen,
     128             :                            SupportedType aType, ErrorResult& rv)
     129             : {
     130           0 :   if (aBufLen > aBuf.Length()) {
     131           0 :     rv.Throw(NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY);
     132           0 :     return nullptr;
     133             :   }
     134           0 :   nsCOMPtr<nsIDOMDocument> domDocument;
     135           0 :   rv = DOMParser::ParseFromBuffer(aBuf.Elements(), aBufLen,
     136             :                                   StringFromSupportedType(aType),
     137           0 :                                   getter_AddRefs(domDocument));
     138           0 :   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
     139           0 :   return document.forget();
     140             : }
     141             : 
     142             : already_AddRefed<nsIDocument>
     143           0 : DOMParser::ParseFromBuffer(const Uint8Array& aBuf, uint32_t aBufLen,
     144             :                            SupportedType aType, ErrorResult& rv)
     145             : {
     146           0 :   aBuf.ComputeLengthAndData();
     147             : 
     148           0 :   if (aBufLen > aBuf.Length()) {
     149           0 :     rv.Throw(NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY);
     150           0 :     return nullptr;
     151             :   }
     152           0 :   nsCOMPtr<nsIDOMDocument> domDocument;
     153           0 :   rv = DOMParser::ParseFromBuffer(aBuf.Data(), aBufLen,
     154             :                                     StringFromSupportedType(aType),
     155           0 :                                     getter_AddRefs(domDocument));
     156           0 :   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
     157           0 :   return document.forget();
     158             : }
     159             : 
     160             : NS_IMETHODIMP
     161           0 : DOMParser::ParseFromBuffer(const uint8_t *buf,
     162             :                            uint32_t bufLen,
     163             :                            const char *contentType,
     164             :                            nsIDOMDocument **aResult)
     165             : {
     166           0 :   NS_ENSURE_ARG_POINTER(buf);
     167           0 :   NS_ENSURE_ARG_POINTER(aResult);
     168             : 
     169             :   // The new stream holds a reference to the buffer
     170           0 :   nsCOMPtr<nsIInputStream> stream;
     171           0 :   nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
     172             :                                       reinterpret_cast<const char *>(buf),
     173           0 :                                       bufLen, NS_ASSIGNMENT_DEPEND);
     174           0 :   if (NS_FAILED(rv))
     175           0 :     return rv;
     176             : 
     177           0 :   return ParseFromStream(stream, nullptr, bufLen, contentType, aResult);
     178             : }
     179             : 
     180             : 
     181             : already_AddRefed<nsIDocument>
     182           0 : DOMParser::ParseFromStream(nsIInputStream* aStream,
     183             :                            const nsAString& aCharset,
     184             :                            int32_t aContentLength,
     185             :                            SupportedType aType,
     186             :                            ErrorResult& rv)
     187             : {
     188           0 :   nsCOMPtr<nsIDOMDocument> domDocument;
     189           0 :   rv = DOMParser::ParseFromStream(aStream,
     190           0 :                                   NS_ConvertUTF16toUTF8(aCharset).get(),
     191             :                                   aContentLength,
     192             :                                   StringFromSupportedType(aType),
     193           0 :                                   getter_AddRefs(domDocument));
     194           0 :   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
     195           0 :   return document.forget();
     196             : }
     197             : 
     198             : NS_IMETHODIMP
     199           0 : DOMParser::ParseFromStream(nsIInputStream *stream,
     200             :                            const char *charset,
     201             :                            int32_t contentLength,
     202             :                            const char *contentType,
     203             :                            nsIDOMDocument **aResult)
     204             : {
     205           0 :   NS_ENSURE_ARG(stream);
     206           0 :   NS_ENSURE_ARG(contentType);
     207           0 :   NS_ENSURE_ARG_POINTER(aResult);
     208           0 :   *aResult = nullptr;
     209             : 
     210           0 :   bool svg = nsCRT::strcmp(contentType, "image/svg+xml") == 0;
     211             : 
     212             :   // For now, we can only create XML documents.
     213             :   //XXXsmaug Should we create an HTMLDocument (in XHTML mode)
     214             :   //         for "application/xhtml+xml"?
     215           0 :   if ((nsCRT::strcmp(contentType, "text/xml") != 0) &&
     216           0 :       (nsCRT::strcmp(contentType, "application/xml") != 0) &&
     217           0 :       (nsCRT::strcmp(contentType, "application/xhtml+xml") != 0) &&
     218           0 :       !svg)
     219           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     220             : 
     221             :   nsresult rv;
     222             : 
     223             :   // Put the nsCOMPtr out here so we hold a ref to the stream as needed
     224           0 :   nsCOMPtr<nsIInputStream> bufferedStream;
     225           0 :   if (!NS_InputStreamIsBuffered(stream)) {
     226           0 :     rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), stream,
     227           0 :                                    4096);
     228           0 :     NS_ENSURE_SUCCESS(rv, rv);
     229             : 
     230           0 :     stream = bufferedStream;
     231             :   }
     232             : 
     233           0 :   nsCOMPtr<nsIDOMDocument> domDocument;
     234           0 :   rv = SetUpDocument(svg ? DocumentFlavorSVG : DocumentFlavorLegacyGuess,
     235           0 :                      getter_AddRefs(domDocument));
     236           0 :   NS_ENSURE_SUCCESS(rv, rv);
     237             : 
     238             :   // Create a fake channel
     239           0 :   nsCOMPtr<nsIChannel> parserChannel;
     240           0 :   NS_NewInputStreamChannel(getter_AddRefs(parserChannel),
     241             :                            mDocumentURI,
     242             :                            nullptr, // aStream
     243             :                            mPrincipal,
     244             :                            nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
     245             :                            nsIContentPolicy::TYPE_OTHER,
     246           0 :                            nsDependentCString(contentType));
     247           0 :   NS_ENSURE_STATE(parserChannel);
     248             : 
     249           0 :   if (charset) {
     250           0 :     parserChannel->SetContentCharset(nsDependentCString(charset));
     251             :   }
     252             : 
     253             :   // Tell the document to start loading
     254           0 :   nsCOMPtr<nsIStreamListener> listener;
     255             : 
     256             :   // Have to pass false for reset here, else the reset will remove
     257             :   // our event listener.  Should that listener addition move to later
     258             :   // than this call?
     259           0 :   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
     260           0 :   if (!document) return NS_ERROR_FAILURE;
     261             : 
     262             :   // Keep the XULXBL state in sync with the HTML case
     263             : 
     264           0 :   if (mOriginalPrincipalWasSystem) {
     265           0 :     document->ForceEnableXULXBL();
     266             :   }
     267             : 
     268           0 :   rv = document->StartDocumentLoad(kLoadAsData, parserChannel,
     269             :                                    nullptr, nullptr,
     270           0 :                                    getter_AddRefs(listener),
     271           0 :                                    false);
     272             : 
     273           0 :   if (NS_FAILED(rv) || !listener) {
     274           0 :     return NS_ERROR_FAILURE;
     275             :   }
     276             : 
     277             :   // Now start pumping data to the listener
     278             :   nsresult status;
     279             : 
     280           0 :   rv = listener->OnStartRequest(parserChannel, nullptr);
     281           0 :   if (NS_FAILED(rv))
     282           0 :     parserChannel->Cancel(rv);
     283           0 :   parserChannel->GetStatus(&status);
     284             : 
     285           0 :   if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(status)) {
     286           0 :     rv = listener->OnDataAvailable(parserChannel, nullptr, stream, 0,
     287           0 :                                    contentLength);
     288           0 :     if (NS_FAILED(rv))
     289           0 :       parserChannel->Cancel(rv);
     290           0 :     parserChannel->GetStatus(&status);
     291             :   }
     292             : 
     293           0 :   rv = listener->OnStopRequest(parserChannel, nullptr, status);
     294             :   // Failure returned from OnStopRequest does not affect the final status of
     295             :   // the channel, so we do not need to call Cancel(rv) as we do above.
     296             : 
     297           0 :   if (NS_FAILED(rv)) {
     298           0 :     return NS_ERROR_FAILURE;
     299             :   }
     300             : 
     301           0 :   domDocument.swap(*aResult);
     302             : 
     303           0 :   return NS_OK;
     304             : }
     305             : 
     306             : NS_IMETHODIMP
     307           0 : DOMParser::Init(nsIPrincipal* principal, nsIURI* documentURI,
     308             :                 nsIURI* baseURI, nsIGlobalObject* aScriptObject)
     309             : {
     310           0 :   NS_ENSURE_STATE(!mAttemptedInit);
     311           0 :   mAttemptedInit = true;
     312           0 :   NS_ENSURE_ARG(principal || documentURI);
     313           0 :   mDocumentURI = documentURI;
     314             : 
     315           0 :   if (!mDocumentURI) {
     316           0 :     principal->GetURI(getter_AddRefs(mDocumentURI));
     317             :     // If we have the system principal, then we'll just use the null principals
     318             :     // uri.
     319           0 :     if (!mDocumentURI && !nsContentUtils::IsSystemPrincipal(principal)) {
     320           0 :       return NS_ERROR_INVALID_ARG;
     321             :     }
     322             :   }
     323             : 
     324           0 :   mScriptHandlingObject = do_GetWeakReference(aScriptObject);
     325           0 :   mPrincipal = principal;
     326             :   nsresult rv;
     327           0 :   if (!mPrincipal) {
     328             :     // BUG 1237080 -- in this case we're getting a chrome privilege scripted
     329             :     // DOMParser object creation without an explicit principal set.  This is
     330             :     // now deprecated.
     331           0 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     332           0 :                                     NS_LITERAL_CSTRING("DOM"),
     333             :                                     nullptr,
     334             :                                     nsContentUtils::eDOM_PROPERTIES,
     335             :                                     "ChromeScriptedDOMParserWithoutPrincipal",
     336             :                                     nullptr,
     337             :                                     0,
     338           0 :                                     documentURI);
     339             : 
     340           0 :     OriginAttributes attrs;
     341           0 :     mPrincipal = BasePrincipal::CreateCodebasePrincipal(mDocumentURI, attrs);
     342           0 :     NS_ENSURE_TRUE(mPrincipal, NS_ERROR_FAILURE);
     343             :   } else {
     344           0 :     if (nsContentUtils::IsSystemPrincipal(mPrincipal)) {
     345             :       // Don't give DOMParsers the system principal.  Use a null
     346             :       // principal instead.
     347           0 :       mOriginalPrincipalWasSystem = true;
     348           0 :       mPrincipal = NullPrincipal::Create();
     349             : 
     350           0 :       if (!mDocumentURI) {
     351           0 :         rv = mPrincipal->GetURI(getter_AddRefs(mDocumentURI));
     352           0 :         NS_ENSURE_SUCCESS(rv, rv);
     353             :       }
     354             :     }
     355             :   }
     356             : 
     357           0 :   mBaseURI = baseURI;
     358             : 
     359           0 :   NS_POSTCONDITION(mPrincipal, "Must have principal");
     360           0 :   NS_POSTCONDITION(mDocumentURI, "Must have document URI");
     361           0 :   return NS_OK;
     362             : }
     363             : 
     364             : /*static */already_AddRefed<DOMParser>
     365           0 : DOMParser::Constructor(const GlobalObject& aOwner,
     366             :                        nsIPrincipal* aPrincipal, nsIURI* aDocumentURI,
     367             :                        nsIURI* aBaseURI, ErrorResult& rv)
     368             : {
     369           0 :   if (aOwner.CallerType() != CallerType::System) {
     370           0 :     rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     371           0 :     return nullptr;
     372             :   }
     373           0 :   RefPtr<DOMParser> domParser = new DOMParser(aOwner.GetAsSupports());
     374           0 :   rv = domParser->InitInternal(aOwner.GetAsSupports(), aPrincipal, aDocumentURI,
     375           0 :                                aBaseURI);
     376           0 :   if (rv.Failed()) {
     377           0 :     return nullptr;
     378             :   }
     379           0 :   return domParser.forget();
     380             : }
     381             : 
     382             : /*static */already_AddRefed<DOMParser>
     383           0 : DOMParser::Constructor(const GlobalObject& aOwner,
     384             :                        ErrorResult& rv)
     385             : {
     386           0 :   RefPtr<DOMParser> domParser = new DOMParser(aOwner.GetAsSupports());
     387           0 :   rv = domParser->InitInternal(aOwner.GetAsSupports(),
     388             :                                nsContentUtils::SubjectPrincipal(),
     389           0 :                                nullptr, nullptr);
     390           0 :   if (rv.Failed()) {
     391           0 :     return nullptr;
     392             :   }
     393           0 :   return domParser.forget();
     394             : }
     395             : 
     396             : nsresult
     397           0 : DOMParser::InitInternal(nsISupports* aOwner, nsIPrincipal* prin,
     398             :                         nsIURI* documentURI, nsIURI* baseURI)
     399             : {
     400           0 :   AttemptedInitMarker marker(&mAttemptedInit);
     401           0 :   if (!documentURI) {
     402             :     // No explicit documentURI; grab document and base URIs off the window our
     403             :     // constructor was called on. Error out if anything untoward happens.
     404             : 
     405             :     // Note that this is a behavior change as far as I can tell -- we're now
     406             :     // using the base URI and document URI of the window off of which the
     407             :     // DOMParser is created, not the window in which parse*() is called.
     408             :     // Does that matter?
     409             : 
     410             :     // Also note that |cx| matches what GetDocumentFromContext() would return,
     411             :     // while GetDocumentFromCaller() gives us the window that the DOMParser()
     412             :     // call was made on.
     413             : 
     414           0 :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aOwner);
     415           0 :     if (!window) {
     416           0 :       return NS_ERROR_UNEXPECTED;
     417             :     }
     418             : 
     419           0 :     baseURI = window->GetDocBaseURI();
     420           0 :     documentURI = window->GetDocumentURI();
     421           0 :     if (!documentURI) {
     422           0 :       return NS_ERROR_UNEXPECTED;
     423             :     }
     424             :   }
     425             : 
     426           0 :   nsCOMPtr<nsIGlobalObject> scriptglobal = do_QueryInterface(aOwner);
     427           0 :   return Init(prin, documentURI, baseURI, scriptglobal);
     428             : }
     429             : 
     430             : void
     431           0 : DOMParser::Init(nsIPrincipal* aPrincipal, nsIURI* aDocumentURI,
     432             :                 nsIURI* aBaseURI, mozilla::ErrorResult& rv)
     433             : {
     434           0 :   AttemptedInitMarker marker(&mAttemptedInit);
     435             : 
     436           0 :   nsCOMPtr<nsIPrincipal> principal = aPrincipal;
     437           0 :   if (!principal && !aDocumentURI) {
     438           0 :     principal = nsContentUtils::SubjectPrincipal();
     439             :   }
     440             : 
     441           0 :   rv = Init(principal, aDocumentURI, aBaseURI, GetEntryGlobal());
     442           0 : }
     443             : 
     444             : nsresult
     445           0 : DOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult)
     446             : {
     447             :   // We should really QI to nsIGlobalObject here, but nsDocument gets confused
     448             :   // if we pass it a scriptHandlingObject that doesn't QI to
     449             :   // nsIScriptGlobalObject, and test_isequalnode.js (an xpcshell test without
     450             :   // a window global) breaks. The correct solution is just to wean nsDocument
     451             :   // off of nsIScriptGlobalObject, but that's a yak to shave another day.
     452             :   nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
     453           0 :     do_QueryReferent(mScriptHandlingObject);
     454             :   nsresult rv;
     455           0 :   if (!mPrincipal) {
     456           0 :     NS_ENSURE_TRUE(!mAttemptedInit, NS_ERROR_NOT_INITIALIZED);
     457           0 :     AttemptedInitMarker marker(&mAttemptedInit);
     458             : 
     459           0 :     nsCOMPtr<nsIPrincipal> prin = NullPrincipal::Create();
     460           0 :     rv = Init(prin, nullptr, nullptr, scriptHandlingObject);
     461           0 :     NS_ENSURE_SUCCESS(rv, rv);
     462             :   }
     463             : 
     464           0 :   NS_ASSERTION(mPrincipal, "Must have principal by now");
     465           0 :   NS_ASSERTION(mDocumentURI, "Must have document URI by now");
     466             : 
     467           0 :   return NS_NewDOMDocument(aResult, EmptyString(), EmptyString(), nullptr,
     468             :                            mDocumentURI, mBaseURI,
     469             :                            mPrincipal,
     470             :                            true,
     471             :                            scriptHandlingObject,
     472           0 :                            aFlavor);
     473             : }

Generated by: LCOV version 1.13